Skip to content

Commit

Permalink
Merge pull request #10 from hasura/lyndon/hide-non-exported-functions
Browse files Browse the repository at this point in the history
Hibernation and function export improvements
  • Loading branch information
sordina authored Sep 22, 2023
2 parents 5e9d6dd + c11be53 commit ba26993
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 33 deletions.
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,9 @@ COPY ./entrypoint.sh ./entrypoint.sh
COPY ./src ./src
COPY ./functions /functions

# Pre-cache inference results and dependencies
RUN echo '{}' > /placeholder-config.json
RUN EARLY_ENTRYPOINT_EXIT=true ./entrypoint.sh /app/ndc-typescript-deno --configuration /placeholder-config.json

ENTRYPOINT [ "./entrypoint.sh", "/app/ndc-typescript-deno"]
CMD ["serve", "--configuration", "/etc/connector/config.json", "--port", "8080"]
22 changes: 10 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The Typescript (Deno) Connector allows a running connector to be inferred from a

The connector runs in the following manner:

* The typescript sources are assembled
* The typescript sources are assembled (with `index.ts` acting as your interface definition)
* Dependencies are fetched into a vendor directory
* Inference is performed and output to schema.json
* The functions are served via HTTP locally in the background with the Deno runtime
Expand All @@ -30,7 +30,7 @@ Your functions should be organised into a directory with one file acting as the

```typescript

// functions/main.ts
// functions/index.ts

import { Hash, encode } from "https://deno.land/x/[email protected]/mod.ts";

Expand Down Expand Up @@ -95,19 +95,17 @@ You will need:
* A value to use with `SERVICE_TOKEN_SECRET`
* A configuration file

The configuration file format needs at a minimum
a `typescript_source` referenced which matches the main
typescript file as mounted with the `--volume` flag.
Your functions directory should be mounted at `/functions` with the `--volume` flag.

```
{"typescript_source": "/functions/main.ts"}
--volume ./my_functions_directory:/functions
```

Create the connector:

> hasura3 connector create my-cool-connector:v1 \\
> --github-repo-url https://github.com/hasura/ndc-typescript-deno/tree/main \\
> --config-file config.json \\
> --config-file <(echo '{}') \\
> --volume ./functions:/functions \\
> --env SERVICE_TOKEN_SECRET=MY-SERVICE-TOKEN
Expand Down Expand Up @@ -206,20 +204,20 @@ For contribution to this connector you will want to have the following dependenc
* [Deno](https://deno.com)
* (Optionally) [Docker](https://www.docker.com)

In order to perform local development, first server your functions:
In order to perform local development, first serve your functions:

* Copy `src/server.ts` into your test `functions/` directory
* Copy your main functions entrypoint (e.g. `functions/main.ts`) to `functions/funcs.ts`
* Switch to your functions directory: `cd functions/`
* Serve yor functions with `deno run --allow-net --allow-sys --allow-env server.ts`
- `server.ts` loads `index.ts` to find your function definitions

In a second shell session perform inference:

* Vendor your dependencies with `deno vendor functions/funcs.ts`
* Perform inference with `deno --allow-net --allow-sys src/infer.ts functions/funcs.ts > schema.json`
* Vendor your dependencies with `deno vendor functions/index.ts`
* Perform inference with `deno --allow-net --allow-sys src/infer.ts functions/index.ts > schema.json`

Then start the connector:

* With the command: `cargo run serve --configuration <(echo '{"typescript_source": "functions/funcs.ts", "schema_location": "./schema.json"}') --port 8100`
* With the command: `cargo run serve --configuration <(echo '{"schema_location": "./schema.json"}') --port 8100`
* You can then test in a Husura project by referencing the connector on `http://localhost:8100`
* Or using the `hasura3` tunnel commands to reference in a Hasura Cloud project
30 changes: 19 additions & 11 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,34 @@

echo "$@"

typescript_source=$(jq -r .typescript_source < /etc/connector/config.json)
typescript_directory=$(dirname "$typescript_source")
typescript_directory=/functions

# TODO: Use filenames that are less likely to conflict
cp src/server.ts "$typescript_directory"
cp src/infer.ts "$typescript_directory"
cp src/deno.d.ts "$typescript_directory"
cp "$typescript_source" "$typescript_directory"/funcs.ts

cd "$typescript_directory"

/root/.deno/bin/deno vendor server.ts
/root/.deno/bin/deno run --allow-env --allow-sys --allow-read --allow-net infer.ts funcs.ts 2>/inference_errors.txt > /schema.json
if [ $? -eq 0 ]
if [ -d vendor ] && [ -f /schema.json ]
then
echo "Inference Successful"
echo "already found vendor and inference results"
else
echo "Inference Failed"
cat /inference_errors.txt
exit 1
/root/.deno/bin/deno vendor -f server.ts
/root/.deno/bin/deno run --allow-env --allow-sys --allow-read --allow-net infer.ts index.ts 2>/inference_errors.txt > /schema.json
if [ $? -eq 0 ]
then
echo "Inference Successful"
else
echo "Inference Failed"
cat /inference_errors.txt
exit 1
fi
fi

if [ "$EARLY_ENTRYPOINT_EXIT" ]
then
echo "Thanks for running pre-caching - Please come again soon!"
exit 0
fi

echo '' | parallel --ungroup --halt-on-error 2 ::: "$*" '/root/.deno/bin/deno run --import-map=vendor/import_map.json --allow-env --allow-net server.ts'
2 changes: 0 additions & 2 deletions src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,13 @@ pub enum TypescriptSource {

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, schemars::JsonSchema)]
pub struct RawConfiguration {
pub typescript_source: Option<TypescriptSource>,
pub schema_location: Option<String>, // Is there a better path type for this?
pub deno_deployment_url: Option<String>,
}

impl Default for RawConfiguration {
fn default() -> RawConfiguration {
RawConfiguration {
typescript_source: None,
schema_location: None,
deno_deployment_url: None,
}
Expand Down
27 changes: 20 additions & 7 deletions src/infer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import ts from "npm:[email protected]";
import ts, { FunctionDeclaration, SyntaxKind } from "npm:[email protected]";
import { resolve } from "https://deno.land/[email protected]/path/posix.ts";
import {existsSync} from "https://deno.land/[email protected]/fs/mod.ts";

Expand Down Expand Up @@ -108,6 +108,15 @@ function programInfo(filename: string) {
"number": "Float",
};

function isExported(node: FunctionDeclaration): boolean {
for(const mod of node.modifiers || []) {
if(mod.kind == ts.SyntaxKind.ExportKeyword) {
return true;
}
}
return false;
}

const validate_type = (name: string, ty: any): ValidateTypeResult => {
const type_str = checker.typeToString(ty);
const type_name = ty.symbol?.escapedName || ty.intrinsicName || 'unknown_type';
Expand Down Expand Up @@ -149,14 +158,12 @@ function programInfo(filename: string) {
return { type: 'named', name: name}
}

// UNHANDLED -- TODO: Make above cases more generic to reduce unhandled errors.
// UNHANDLED: Assume that the type is a scalar
else {
// console.debug(ty);
console.error(`Unable to validate type of ${name}: ${type_str}.`);
Deno.exit(1); // Proceed
console.error(`Unable to validate type of ${name}: ${type_str}. Assuming that it is a scalar type.`);
schema_response.scalar_types[name] = no_ops;
return { type: 'named', name };
}

return { type: 'named', name: 'IMPOSSIBLE'}; // Satisfy TS Checker.
}

for (const src of program.getSourceFiles()) {
Expand All @@ -167,6 +174,12 @@ function programInfo(filename: string) {
if (ts.isFunctionDeclaration(node)) {
const fn_sym = checker.getSymbolAtLocation(node.name!)!;
const fn_name = fn_sym.escapedName;

if(!isExported(node)) {
console.error(`Skipping non-exported function: ${fn_name}`);
return;
}

const fn_type = checker.getTypeOfSymbolAtLocation(fn_sym, fn_sym.valueDeclaration!);
const fn_desc = ts.displayPartsToString(fn_sym.getDocumentationComment(checker));
const fn_tags = fn_sym.getJsDocTags();
Expand Down
2 changes: 1 addition & 1 deletion src/server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Application, Router } from "https://deno.land/x/[email protected]/mod.ts";
import { oakCors } from "https://deno.land/x/[email protected]/mod.ts";
import * as importedFuncs from "./funcs.ts"
import * as importedFuncs from "./index.ts"

type FunctionInvocation = {
functionName: string,
Expand Down

0 comments on commit ba26993

Please sign in to comment.