From eda5c12f3c46294b4f1ad444259648ce893f3dda Mon Sep 17 00:00:00 2001 From: afmika Date: Wed, 14 Feb 2024 17:46:03 +0300 Subject: [PATCH] refactor(cli/sdk): move all preps to sdk (wip) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat(sdk): testing framework integration 2 (#579) Continuation of #566 , focused on prisma runtime. N/A - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change --------- Signed-off-by: Michaël refactor(sdk): move post-processing functions to the typegate (#586) Depends on #579 Compiled `wasm` bin size is too large, goal is to reduce it to ~3MB. N/A - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change --------- Signed-off-by: Michaël Co-authored-by: Natoandro feat(sdk): prepare client (wip) feat: Remove obsolete restrictions on prisma (#592) Since v5, where on unique queries exposes all the fields, not just unique fields. Reference: https://www.prisma.io/docs/orm/reference/prisma-client-reference#filter-on-non-unique-fields-with-userwhereuniqueinput - [x] The change come with new or modified tests - [x] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change feat(sdk): change finalization logic (wip) fix: Show error message for unregistered type name (#594) Check and throw the error for the `expose` function when called from the Python SDK. We got a finalization failure when there are some unregistered type referenced with `g.ref`. _No changes needed._ - [x] The change come with new or modified tests - [x] Hard-to-understand functions have explanatory comments - [x] End-user documentation is updated to reflect the change feat: Parameter transformation (#587) Enable parameter transformation with the `.apply()` method. It has more or less the same logic as `.reduce()` with the ability to flatten the input type. This feature enables simpler APIs (input types) on top of runtimes (e.g.: prisma). _No changes needed_. - [x] The change come with new or modified tests - [x] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change feat(sdk): change finalization logic + serialization (wip) feat(sdk): serialization (wip) feat(sdk): from_random injection (#593) This change includes changes in StringFormats(added some string formats), logic to provide random values for type nodes and tests to validate the changes. The changes are mostly in the typegraph sdk. This feature enables the user to inject random values for a field(**Type Node**) when defining a **Typegraph**. _No changes needed_. - [x] The change come with new or modified tests - [x] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change fix(cli): threads pointing to different mem loc feat(sdk): serialize (wip) feat(sdk): print serialized version fix(examples): add top level await fix(cli): conflicting ports feat(sdk): undeploy feat(cli): prepare undeploy feat(cli): prepare deploy feat(cli): deploy (wip) feat(cli/sdk): store response feat(cli/sdk): id by path scheme + pass migration flags fix(cli): pass value feat(cli): deploy without migration fix(cli): loader event not firing when serialize chore: remove unwanted file feat!: Nested context query (#595) - Revert context flattening - Enable jsonpath-like key to access nested object fields or array items on the context. If you access the context directly in your application (through the token), access to nested fields shall be updated. E.g. the expression `context["profile.id"]` have to turned to `context.profile.id`. - [x] The change come with new or modified tests - [x] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change fix: remove injections from prisma output types (#597) Remove injections from generated output types for prisma operations. Generated types fail validations (_injection not allowed in output types_). _No changes needed_. - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change feat(deno/sdk): native function embedding in typescript (#598) Add support for function or lambda definition typescript sdk for `deno.func` similarly to how `python.from_def` in python sdk works. Providing a string is a bit impractical and counter-intuitive espcially when the sdk language matches with runtime's language. No changes needed. - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change --------- Signed-off-by: Michaël fix(cli): fix for `meta-cli deploy` exit with code `0` on failure (#600) fix the issue where `meta-cli deploy` command exits with code 0 on failure. bug fix No changes needed. - [ ] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change feat(sdk): rework deploy command with new scheme chore(examples): rm debug line feat(cli/sdk): set prefix when the typegraph is loaded fix(cli): retry bug (wip) fix(cli): bind directly from pre-allocated tcplistener chore(deps): Bump the deps group in /website with 13 updates (#604) Bumps the deps group in /website with 13 updates: | Package | From | To | | --- | --- | --- | | [@apollo/client](https://github.com/apollographql/apollo-client) | `3.9.1` | `3.9.5` | | [@giscus/react](https://github.com/giscus/giscus-component/tree/HEAD/react) | `2.4.0` | `3.0.0` | | [@graphiql/react](https://github.com/graphql/graphiql/tree/HEAD/packages/graphiql-react) | `0.20.2` | `0.20.3` | | [graphiql](https://github.com/graphql/graphiql/tree/HEAD/packages/graphiql) | `3.1.0` | `3.1.1` | | [graphql-ws](https://github.com/enisdenjo/graphql-ws) | `5.14.3` | `5.15.0` | | [konva](https://github.com/konvajs/konva) | `9.3.2` | `9.3.3` | | [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `18.2.48` | `18.2.61` | | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `6.20.0` | `7.1.0` | | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `6.20.0` | `7.1.0` | | [eslint](https://github.com/eslint/eslint) | `8.56.0` | `8.57.0` | | [sass](https://github.com/sass/dart-sass) | `1.70.0` | `1.71.1` | | [sass-loader](https://github.com/webpack-contrib/sass-loader) | `14.1.0` | `14.1.1` | | [webpack](https://github.com/webpack/webpack) | `5.90.0` | `5.90.3` | Updates `@apollo/client` from 3.9.1 to 3.9.5
Release notes

Sourced from @​apollo/client's releases.

v3.9.5

Patch Changes

v3.9.4

Patch Changes

v3.9.3

Patch Changes

v3.9.2

Patch Changes

Changelog

Sourced from @​apollo/client's changelog.

3.9.5

Patch Changes

3.9.4

Patch Changes

3.9.3

Patch Changes

3.9.2

Patch Changes

Commits
  • 17ccc42 3.9.5 release (#11580)
  • 1133469 fix: strengthen MockedResponse.newData type (#11592)
  • a0d40aa Fix anchor links in ApolloClient api docs (#11599)
  • 1ba2fd9 Fix regression that causes partial data to be reported unexpectedly in some c...
  • 8c20955 bump rehackt to v0.0.5 (#11595)
  • ac4ae84 chore(deps): update all devdependencies (#11586)
  • 6933e0e chore(deps): update mad9000/actions-find-and-replace-string action to v5 (#11...
  • 9cba37c chore(deps): update all dependencies - patch updates (#11585)
  • d46acaf Update ROADMAP.md
  • 65ab695 Make mock response error and result optional when delay is infinite (#11562)
  • Additional commits viewable in compare view

Updates `@giscus/react` from 2.4.0 to 3.0.0
Release notes

Sourced from @​giscus/react's releases.

@​giscus/react v3.0.0

Added

  • Update types with new available languages and themes.

Changed

  • Breaking: drop CommonJS support. This package is now ESM-only (#1998).

Fixed

  • Fix incompatibility with Next.js 14.1 when using the app router (#1976).
Commits
  • ad31fa6 common: Bump versions
  • f71ba9b common: Update types
  • 77f6fb0 react: Format config files too
  • 36973ff react: Export as pure ESM
  • e8417b2 common: Update dependencies
  • 111050c react: Remove packaged 2.3.0
  • 13d5043 build(deps-dev): bump the react group in /react with 6 updates
  • 33dcbb2 build(deps-dev): bump the react group in /react with 5 updates
  • 268fbcd build(deps-dev): bump the react group in /react with 7 updates
  • 46718bc build(deps-dev): bump the react group in /react with 6 updates
  • Additional commits viewable in compare view

Updates `@graphiql/react` from 0.20.2 to 0.20.3
Release notes

Sourced from @​graphiql/react's releases.

@​graphiql/react@​0.20.3

Patch Changes

  • #3526 2b6ea316 Thanks @​benjie! - Add new useOptimisticState hook that can wrap a useState-like hook to perform optimistic caching of state changes, this helps to avoid losing characters when the user is typing rapidly. Example of usage: const [state, setState] = useOptimisticState(useOperationsEditorState());
Changelog

Sourced from @​graphiql/react's changelog.

0.20.3

Patch Changes

  • #3526 2b6ea316 Thanks @​benjie! - Add new useOptimisticState hook that can wrap a useState-like hook to perform optimistic caching of state changes, this helps to avoid losing characters when the user is typing rapidly. Example of usage: const [state, setState] = useOptimisticState(useOperationsEditorState());
Commits

Updates `graphiql` from 3.1.0 to 3.1.1
Release notes

Sourced from graphiql's releases.

graphiql@3.1.1

Patch Changes

Changelog

Sourced from graphiql's changelog.

3.1.1

Patch Changes

Commits

Updates `graphql-ws` from 5.14.3 to 5.15.0
Release notes

Sourced from graphql-ws's releases.

v5.15.0

5.15.0 (2024-02-12)

Bug Fixes

  • client: Use TerminatedCloseEvent class extending an Error for rejecting promises when terminating (74b4ceb), closes #531
  • server: Dispose of subscriptions on close even if added late to the subscriptions list (#534) (e45d6b1), closes #532

Features

  • server: Add is retry flag to connect events (#507) (9ad853f)
Changelog

Sourced from graphql-ws's changelog.

5.15.0 (2024-02-12)

Bug Fixes

  • client: Use TerminatedCloseEvent class extending an Error for rejecting promises when terminating (74b4ceb), closes #531
  • server: Dispose of subscriptions on close even if added late to the subscriptions list (#534) (e45d6b1), closes #532

Features

  • server: Add is retry flag to connect events (#507) (9ad853f)
Commits
  • 933d720 chore(release): 🎉 5.15.0 [skip ci]
  • 74b4ceb fix(client): Use TerminatedCloseEvent class extending an Error for reject...
  • f76bb54 test: update expected arguments for connecting event
  • 9ad853f feat(server): Add is retry flag to connect events (#507)
  • e45d6b1 fix(server): Dispose of subscriptions on close even if added late to the subs...
  • e2603be chore: revert pkg workspaces after pack
  • 8d3f3d0 chore(deps): update lockfile
  • c61e31b refactor: return of the website workspace
  • e19263e chore(deps): update lockfile
  • 69791ee docs(bun): correct handleProtocols usage
  • See full diff in compare view

Updates `konva` from 9.3.2 to 9.3.3
Release notes

Sourced from konva's releases.

9.3.3

Commits

  • 4da037a: Another fix for exporting buffered shapes (Anton Lavrenov)
  • 93106ab: update CHANGELOG with new version (Anton Lavrenov)
  • ea92753: build for 9.3.3 (Anton Lavrenov)
  • e767285: update cdn link (Anton Lavrenov)
Changelog

Sourced from konva's changelog.

9.3.3 (2024-02-09)

  • Another fix for exporting buffered shapes
Commits

Updates `@types/react` from 18.2.48 to 18.2.61
Commits

Updates `@typescript-eslint/eslint-plugin` from 6.20.0 to 7.1.0
Release notes

Sourced from @​typescript-eslint/eslint-plugin's releases.

v7.1.0

7.1.0 (2024-02-26)

🚀 Features

  • eslint-plugin: add *-type-checked-only configs (#8367)
  • eslint-plugin: [naming-convention] support the auto-accessor syntax (#8084)
  • eslint-plugin: [consistent-return] add new rule (#8289)
  • typescript-estree: add debug logs for useProgramFromProjectService (#8426)

🩹 Fixes

  • eslint-plugin: [prefer-optional-chan] allow typeof for avoiding reference error (#8472)
  • eslint-plugin: [no-misused-promises] improve check union types (#8534)
  • eslint-plugin: [no-use-before-define] fix false positive type reference in as, satisfies (#8474)
  • typescript-estree: use simpler absolutify behavior for project service client file paths (#8520)

❤️ Thank You

You can read about our versioning strategy and releases on our website.

v7.0.2

7.0.2 (2024-02-19)

🩹 Fixes

  • fix tsconfig-less check errors, fix @types/eslint incompatibilities, add tests (#8460)
  • utils: use mergeable interface for settings property (#8485)

❤️ Thank You

You can read about our versioning strategy and releases on our website.

v7.0.1

7.0.1 (2024-02-12)

🩹 Fixes

  • eslint-plugin: update peer dep for parser (#8441)

... (truncated)

Changelog

Sourced from @​typescript-eslint/eslint-plugin's changelog.

7.1.0 (2024-02-26)

🚀 Features

  • eslint-plugin: add *-type-checked-only configs

  • eslint-plugin: [naming-convention] support the auto-accessor syntax

  • eslint-plugin: [consistent-return] add new rule

🩹 Fixes

  • eslint-plugin: [prefer-optional-chan] allow typeof for avoiding reference error

  • eslint-plugin: [no-misused-promises] improve check union types

  • eslint-plugin: [no-use-before-define] fix false positive type reference in as, satisfies

❤️ Thank You

  • Arka Pratim Chaudhuri
  • Josh Goldberg ✨
  • YeonJuan

You can read about our versioning strategy and releases on our website.

7.0.2 (2024-02-19)

🩹 Fixes

  • fix tsconfig-less check errors, fix @types/eslint incompatibilities, add tests

❤️ Thank You

  • Brad Zacher
  • Gareth Jones

You can read about our versioning strategy and releases on our website.

7.0.1 (2024-02-12)

🩹 Fixes

  • eslint-plugin: update peer dep for parser

... (truncated)

Commits
  • 4bc6944 chore(release): publish 7.1.0
  • 1807d55 docs: add tabs in no-unsafe-unary-minus.md (#8542)
  • f2f57de test(eslint-plugin): [no-misused-promises] add test cases for spread args (#8...
  • fa67955 chore: drop T from internal types (#8521)
  • 60c1cd3 fix(eslint-plugin): [no-use-before-define] fix false positive type reference ...
  • 1458920 fix(eslint-plugin): [no-misused-promises] improve check union types (#8534)
  • c1441c8 fix(eslint-plugin): [prefer-optional-chan] allow typeof for avoiding referenc...
  • e7ec6f0 docs: from option instead of source in prefer-readonly-parameter-types (#8461)
  • 46cef96 feat(eslint-plugin): [consistent-return] add new rule (#8289)
  • f7198db feat(eslint-plugin): [naming-convention] support the auto-accessor syntax (#8...
  • Additional commits viewable in compare view

Updates `@typescript-eslint/parser` from 6.20.0 to 7.1.0
Release notes

Sourced from @​typescript-eslint/parser's releases.

v7.1.0

7.1.0 (2024-02-26)

🚀 Features

  • eslint-plugin: add *-type-checked-only configs (#8367)
  • eslint-plugin: [naming-convention] support the auto-accessor syntax (#8084)
  • eslint-plugin: [consistent-return] add new rule (#8289)
  • typescript-estree: add debug logs for useProgramFromProjectService (#8426)

🩹 Fixes

  • eslint-plugin: [prefer-optional-chan] allow typeof for avoiding reference error (#8472)
  • eslint-plugin: [no-misused-promises] improve check union types (#8534)
  • eslint-plugin: [no-use-before-define] fix false positive type reference in as, satisfies (#8474)
  • typescript-estree: use simpler absolutify behavior for project service client file paths (#8520)

❤️ Thank You

You can read about our versioning strategy and releases on our website.

v7.0.2

7.0.2 (2024-02-19)

🩹 Fixes

  • fix tsconfig-less check errors, fix @types/eslint incompatibilities, add tests (#8460)
  • utils: use mergeable interface for settings property (#8485)

❤️ Thank You

You can read about our versioning strategy and releases on our website.

v7.0.1

7.0.1 (2024-02-12)

🩹 Fixes

  • eslint-plugin: update peer dep for parser (#8441)

... (truncated)

Changelog

Sourced from @​typescript-eslint/parser's changelog.

7.1.0 (2024-02-26)

This was a version bump only for parser to align it with other projects, there were no code changes.

You can read about our versioning strategy and releases on our website.

7.0.2 (2024-02-19)

🩹 Fixes

  • fix tsconfig-less check errors, fix @types/eslint incompatibilities, add tests

❤️ Thank You

  • Brad Zacher
  • Gareth Jones

You can read about our versioning strategy and releases on our website.

7.0.1 (2024-02-12)

This was a version bump only for parser to align it with other projects, there were no code changes.

You can read about our versioning strategy and releases on our website.

7.0.0 (2024-02-12)

🚀 Features

  • ⚠️ bump ESLint, NodeJS, and TS minimum version requirements

  • add support for flat configs

⚠️ Breaking Changes

  • ⚠️ bump ESLint, NodeJS, and TS minimum version requirements

❤️ Thank You

  • Brad Zacher
  • Kirk Waiblinger
  • StyleShit
  • YeonJuan

You can read about our versioning strategy and releases on our website.

... (truncated)

Commits
  • 4bc6944 chore(release): publish 7.1.0
  • 677e7cc chore(release): publish 7.0.2
  • 4f3215f chore(release): publish 7.0.1
  • b27de99 chore(release): publish 7.0.0
  • 1aa393c chore(deps): update dependency prettier to v3.2.5 (#8401)
  • 8ef5f4b feat: add support for flat configs (#7935)
  • 1200b4c chore(deps): update nx to v17.3.0 (#8317)
  • 584db29 feat: bump ESLint, NodeJS, and TS minimum version requirements (#8377)
  • 289ee88 chore(release): publish 6.21.0
  • aa5edf7 chore(deps): update dependency prettier to v3.2.4 (#8357)
  • Additional commits viewable in compare view

Updates `eslint` from 8.56.0 to 8.57.0
Release notes

Sourced from eslint's releases.

v8.57.0

Features

  • 1120b9b feat: Add loadESLint() API method for v8 (#18098) (Nicholas C. Zakas)
  • dca7d0f feat: Enable eslint.config.mjs and eslint.config.cjs (#18066) (Nitin Kumar)

Bug Fixes

  • 2196d97 fix: handle absolute file paths in FlatRuleTester (#18064) (Nitin Kumar)
  • 69dd1d1 fix: Ensure config keys are printed for config errors (#18067) (Nitin Kumar)
  • 9852a31 fix: deep merge behavior in flat config (#18065) (Nitin Kumar)
  • 4c7e9b0 fix: allow circular references in config (#18056) (Milos Djermanovic)

Documentation

  • 84922d0 docs: Show prerelease version in dropdown (#18139) (Nicholas C. Zakas)
  • 5b8c363 docs: Switch to Ethical Ads (#18117) (Milos Djermanovic)
  • 77dbfd9 docs: show NEXT in version selectors (#18052) (Milos Djermanovic)

Chores

  • 1813aec chore: upgrade @​eslint/js@​8.57.0 (#18143) (Milos Djermanovic)
  • 5c356bb chore: package.json update for @​eslint/js release (Jenkins)
  • f4a1fe2 test: add more tests for ignoring files and directories (#18068) (Nitin Kumar)
  • 42c0aef ci: Enable CI for v8.x branch (#18047) (Milos Djermanovic)
Changelog

Sourced from eslint's changelog.

v8.57.0 - February 23, 2024

  • 1813aec chore: upgrade @​eslint/js@​8.57.0 (#18143) (Milos Djermanovic)
  • 5c356bb chore: package.json update for @​eslint/js release (Jenkins)
  • 84922d0 docs: Show prerelease version in dropdown (#18139) (Nicholas C. Zakas)
  • 1120b9b feat: Add loadESLint() API method for v8 (#18098) (Nicholas C. Zakas)
  • 5b8c363 docs: Switch to Ethical Ads (#18117) (Milos Djermanovic)
  • 2196d97 fix: handle absolute file paths in FlatRuleTester (#18064) (Nitin Kumar)
  • f4a1fe2 test: add more tests for ignoring files and directories (#18068) (Nitin Kumar)
  • 69dd1d1 fix: Ensure config keys are printed for config errors (#18067) (Nitin Kumar)
  • 9852a31 fix: deep merge behavior in flat config (#18065) (Nitin Kumar)
  • dca7d0f feat: Enable eslint.config.mjs and eslint.config.cjs (#18066) (Nitin Kumar)
  • 4c7e9b0 fix: allow circular references in config (#18056) (Milos Djermanovic)
  • 77dbfd9 docs: show NEXT in version selectors (#18052) (Milos Djermanovic)
  • 42c0aef ci: Enable CI for v8.x branch (#18047) (Milos Djermanovic)

v9.0.0-beta.0 - February 9, 2024

  • e40d1d7 chore: upgrade @​eslint/js@​9.0.0-beta.0 (#18108) (Milos Djermanovic)
  • 9870f93 chore: package.json update for @​eslint/js release (Jenkins)
  • 2c62e79 chore: upgrade @​eslint/eslintrc@​3.0.1 (#18107) (Milos Djermanovic)
  • 81f0294 chore: upgrade espree@10.0.1 (#18106) (Milos Djermanovic)
  • 5e2b292 chore: upgrade eslint-visitor-keys@4.0.0 (#18105) (Milos Djermanovic)
  • 9163646 feat!: Rule Tester checks for missing placeholder data in the message (#18073) (fnx)
  • 53f0f47 feat: Add loadESLint() API method for v9 (#18097) (Nicholas C. Zakas)
  • f1c7e6f docs: Switch to Ethical Ads (#18090) (Strek)
  • 15c143f docs: JS Foundation -> OpenJS Foundation in PR template (#18092) (Nicholas C. Zakas)
  • c4d26fd fix: use-isnan doesn't report on SequenceExpressions (#18059) (StyleShit)
  • 6ea339e docs: add stricter rule test validations to v9 migration guide (#18085) (Milos Djermanovic)
  • ce838ad chore: replace dependency npm-run-all with npm-run-all2 ^5.0.0 (#18045) (renovate[bot])
  • 3c816f1 docs: use relative link from CLI to core concepts (#18083) (Milos Djermanovic)
  • 54df731 chore: update dependency markdownlint-cli to ^0.39.0 (#18084) (renovate[bot])
  • 9458735 docs: fix malformed eslint config comments in rule examples (#18078) (Francesco Trotta)
  • 07a1ada docs: link from --fix CLI doc to the relevant core concept (#18080) (Bryan Mishkin)
  • 8f06a60 chore: update dependency shelljs to ^0.8.5 (#18079) (Francesco Trotta)
  • b844324 docs: Update team responsibilities (#18048) (Nicholas C. Zakas)
  • aadfb60 docs: document languageOptions and other v9 changes for context (#18074) (fnx)
  • 3c4d51d feat!: default for enforceForClassMembers in no-useless-computed-key (#18054) (Francesco Trotta)
  • 47e60f8 feat!: Stricter rule test validations (#17654) (fnx)
  • 1a94589 feat!: no-unused-vars default caughtErrors to 'all' (#18043) (Josh Goldberg ✨)
  • 857e242 docs: tweak explanation for meta.docs rule properties (#18057) (Bryan Mishkin)
  • 10485e8 docs: recommend messageId over message for reporting rule violations (#18050) (Bryan Mishkin)
  • 98b5ab4 docs: Update README (GitHub Actions Bot)
  • 93ffe30 chore: update dependency file-entry-cache to v8 (#17903) (renovate[bot])
  • 505fbf4 docs: update no-restricted-imports rule (#18015) (Tanuj Kanti)
  • 2d11d46 feat: add suggestions to use-isnan in binary expressions (#17996) (StyleShit)
  • c25b4af docs: Update README (GitHub Actions Bot)

v9.0.0-alpha.2 - January 26, 2024

... (truncated)

Commits

Updates `sass` from 1.70.0 to 1.71.1
Release notes

Sourced from sass's releases.

Dart Sass 1.71.1

To install Sass 1.71.1, download one of the packages below and add it to your PATH, or see the Sass website for full installation instructions.

Changes

Command-Line Interface

  • Ship the musl Linux release with the proper Dart executable.

JavaScript API

  • Export the NodePackageImporter class in ESM mode.

  • Allow NodePackageImporter to locate a default directory even when the entrypoint is an ESM module.

Dart API

  • Make passing a null argument to NodePackageImporter() a static error rather than just a runtime error.

Embedded Sass

  • In the JS Embedded Host, properly install the musl Linux embedded compiler when running on musl Linux.

See the full changelog for changes in earlier releases.

Dart Sass 1.71.0

To install Sass 1.71.0, download one of the packages below and add it to your PATH, or see the Sass website for full installation instructions.

Changes

For more information about pkg: importers, see the announcement on the Sass blog.

Command-Line Interface

  • Add a --pkg-importer flag to enable built-in pkg: importers. Currently this only supports the Node.js package resolution algorithm, via --pkg-importer=node. For example, @use "pkg:bootstrap" will load node_modules/bootstrap/scss/bootstrap.scss.

JavaScript API

  • Add a NodePackageImporter importer that can be passed to the importers option. This loads files using the pkg: URL scheme according to the Node.js package resolution algorithm. For example, @use "pkg:bootstrap" will load node_modules/bootstrap/scss/bootstra... _Description has been truncated_ Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> chore(deps): Bump @mdx-js/react from 3.0.0 to 3.0.1 in /website (#605) Bumps [@mdx-js/react](https://github.com/mdx-js/mdx/tree/HEAD/packages/react) from 3.0.0 to 3.0.1.
    Release notes

    Sourced from @​mdx-js/react's releases.

    3.0.1

    Fix

    Types

    Site

    Full Changelog: https://github.com/mdx-js/mdx/compare/3.0.0...3.0.1

    Commits

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@mdx-js/react&package-manager=npm_and_yarn&previous-version=3.0.0&new-version=3.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> feat(cli): basic retry on failure feat(cli): retry on failure fix(cli): forced panic in default mode feat(sdk/sdk): python client fix(cli): cover missed events fix(sdk): always sync target version fix(cli): unreachable loader event when no files are provided feat(sdk/python): serialize feat(sdk/python): deploy fix(sdk/python/e2e): circular imports fix(cli): dir => root typegraph, migration paths => relative to dir fix(typegate,typegraph): minor bugs (#596) Just a few very minor bugs I'd encountered this week. Tests pending. Bugs. _No changes required_ - [ ] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change fix: esm customizer for typegate deno ext (#606) Enables v8 snapshots integration for `meta typegate` subcommand and the standalone typegate. Also bumps deno to 1.41.0. Fixes #591 _No changes required_ - [ ] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change refactor!: make fat `meta-cli` the default (#607) Switch the default `meta-cli` release to the fat version (the one that includes the `typegate` subcommand). Tackles #MET-400 The fat cli requires `libwasmedge.so` to be present. Users will need to install or switch to the `meta-cli-thin` release. - [ ] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [x] End-user documentation is updated to reflect the change fix: re-enable macos-latest cli-compat test job (#608) Fixes and enables the broken job. Job was disabled earlier to mysterious breakages. __No changes required__ - [ ] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change chore(release): bump 0.3.5 (#613) Ready for release of v0.3.5 Required by console. _No changes required__. - [ ] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change fix(sdk): tarball yields wrong rel. path when sdk is spawn from another process test(cli): disable codegen fix(sdk): cover empty list edgecase fix(cli): increase payload size fix(cli): run server only on specific commands feat(cli): database reset interactive (wip) fix(sdk): never decide on a default migration path on sdk fix(sdk/python): migration not considered feat(cli): database reset live interaction feat(cli): migration failure on nullconstraint (wip) fix(cli): stdout out of order for Confirm test(e2e): temporary disable dev migration test fix: apply from context (#616) Fix type validators for apply from context. Bug. _N/A_ - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change fix(python-wasi): fix for vm not initialized after consecutive deploy (#617) Bug fix for typegate throwing `vm not initialized` after reload Bug fix No Migrations Needed - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change fix(gate): `RandomRuntime` does not consider `enum`, `either`, `union` variants (#619) add either, enum, struct and union type support in Random Runtime. generating random values for enums, either and union types was failing. _No Migrations Needed - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change feat(sdk): allow MigrationAction to be configurable per runtime name feat(sdk): multiple choices on failed migration feat(cli): remove duplicate action fix(cli): run the server on the appropriate command test(template): fix outdated sdks fix(website): disable empty typegraph fix(test): name clash + update self_deploy test(e2e): missing runtime name when removing a file chore(cli/sdk): remove unused code test(validation): delegate validation to sdk feat(sdk): make config optional for the global postprocessor chore(release): prepare for 0.3.6-0 (#615) Automatic suggested bump Co-authored-by: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> chore(deps-dev): Bump the deps group with 1 update (#601) Bumps the deps group with 1 update: [ruff](https://github.com/astral-sh/ruff). Updates `ruff` from 0.1.15 to 0.3.0
    Release notes

    Sourced from ruff's releases.

    v0.3.0

    This release introduces the new Ruff formatter 2024.2 style and adds a new lint rule to detect invalid formatter suppression comments.

    Changes

    Preview features

    • [flake8-bandit] Remove suspicious-lxml-import (S410) (#10154)
    • [pycodestyle] Allow os.environ modifications between imports (E402) (#10066)
    • [pycodestyle] Don't warn about a single whitespace character before a comma in a tuple (E203) (#10094)

    Rule changes

    • [eradicate] Detect commented out case statements (ERA001) (#10055)
    • [eradicate] Detect single-line code for try:, except:, etc. (ERA001) (#10057)
    • [flake8-boolean-trap] Allow boolean positionals in __post_init__ (#10027)
    • [flake8-copyright] Allow © in copyright notices (#10065)
    • [isort]: Use one blank line after imports in typing stub files (#9971)
    • [pylint] New Rule dict-iter-missing-items (PLE1141) (#9845)
    • [pylint] Ignore sys.version and sys.platform (PLR1714) (#10054)
    • [pyupgrade] Detect literals with unary operators (UP018) (#10060)
    • [ruff] Expand rule for list(iterable).pop(0) idiom (RUF015) (#10148)

    Formatter

    This release introduces the Ruff 2024.2 style, stabilizing the following changes:

    • Prefer splitting the assignment's value over the target or type annotation (#8943)
    • Remove blank lines before class docstrings (#9154)
    • Wrap multiple context managers in with parentheses when targeting Python 3.9 or newer (#9222)
    • Add a blank line after nested classes with a dummy body (...) in typing stub files (#9155)
    • Reduce vertical spacing for classes and functions with a dummy (...) body (#7440, #9240)
    • Add a blank line after the module docstring (#8283)
    • Parenthesize long type hints in assignments (#9210)
    • Preserve indent for single multiline-string call-expressions (#9673)
    • Normalize hex escape and unicode escape sequences (#9280)
    • Format module docstrings (#9725)

    CLI

    • Explicitly disallow extend as part of a --config flag (#10135)
    • Remove build from the default exclusion list (#10093)
    • Deprecate ruff <path>, ruff --explain, ruff --clean, and ruff --generate-shell-completion in favor of ruff check <path>, ruff rule, ruff clean, and ruff generate-shell-completion (#10169)
    • Remove the deprecated CLI option --format from ruff rule and ruff linter (#10170)

    Bug fixes

    • [flake8-bugbear] Avoid adding default initializers to stubs (B006) (#10152)
    • [flake8-type-checking] Respect runtime-required decorators for function signatures (#10091)

    ... (truncated)

    Changelog

    Sourced from ruff's changelog.

    0.3.0

    This release introduces the new Ruff formatter 2024.2 style and adds a new lint rule to detect invalid formatter suppression comments.

    Preview features

    • [flake8-bandit] Remove suspicious-lxml-import (S410) (#10154)
    • [pycodestyle] Allow os.environ modifications between imports (E402) (#10066)
    • [pycodestyle] Don't warn about a single whitespace character before a comma in a tuple (E203) (#10094)

    Rule changes

    • [eradicate] Detect commented out case statements (ERA001) (#10055)
    • [eradicate] Detect single-line code for try:, except:, etc. (ERA001) (#10057)
    • [flake8-boolean-trap] Allow boolean positionals in __post_init__ (#10027)
    • [flake8-copyright] Allow © in copyright notices (#10065)
    • [isort]: Use one blank line after imports in typing stub files (#9971)
    • [pylint] New Rule dict-iter-missing-items (PLE1141) (#9845)
    • [pylint] Ignore sys.version and sys.platform (PLR1714) (#10054)
    • [pyupgrade] Detect literals with unary operators (UP018) (#10060)
    • [ruff] Expand rule for list(iterable).pop(0) idiom (RUF015) (#10148)

    Formatter

    This release introduces the Ruff 2024.2 style, stabilizing the following changes:

    • Prefer splitting the assignment's value over the target or type annotation (#8943)
    • Remove blank lines before class docstrings (#9154)
    • Wrap multiple context managers in with parentheses when targeting Python 3.9 or newer (#9222)
    • Add a blank line after nested classes with a dummy body (...) in typing stub files (#9155)
    • Reduce vertical spacing for classes and functions with a dummy (...) body (#7440, #9240)
    • Add a blank line after the module docstring (#8283)
    • Parenthesize long type hints in assignments (#9210)
    • Preserve indent for single multiline-string call-expressions (#9673)
    • Normalize hex escape and unicode escape sequences (#9280)
    • Format module docstrings (#9725)

    CLI

    • Explicitly disallow extend as part of a --config flag (#10135)
    • Remove build from the default exclusion list (#10093)
    • Deprecate ruff <path>, ruff --explain, ruff --clean, and ruff --generate-shell-completion in favor of ruff check <path>, ruff rule, ruff clean, and ruff generate-shell-completion (#10169)
    • Remove the deprecated CLI option --format from ruff rule and ruff linter (#10170)

    Bug fixes

    • [flake8-bugbear] Avoid adding default initializers to stubs (B006) (#10152)
    • [flake8-type-checking] Respect runtime-required decorators for function signatures (#10091)
    • [pycodestyle] Mark fixes overlapping with a multiline string as unsafe (W293) (#10049)

    ... (truncated)

    Commits

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ruff&package-manager=pip&previous-version=0.1.15&new-version=0.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> test(e2e): make sure test does not depend on the version + debug collected files on ci fix: support multiple typegraph in a single file address comments fix: rename query variable fix: Optimize typegraph size (#618) - Hash all type data to compare them on the conversion phase in typegraph/core: remove duplicate types from type final typegraph (duplicate: same value for all the fields except for the "random" name/title). - Skip unreferenced types in `.apply` Typegraph is too big sometimes. - [ ] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change fix: typegate.json chore(sdk): add hash compute function and field to store it chore(sdk, gate): add ref_files to tg.meta during tg conversion feat(gate): add getUploadUrl endpoint and one time endpoint to upload file feat(sdk): add refereed files getter from the global store feat(gate): add cache to store used urls and add file upload at tg_deploy feat(gate): change to open the artifacts from the typegate engine feat(gate): sign upload url feat(core_sdk): remove reading file and replace with upload url feat(gate): update prisma migrations and read wasm file in engine chore(sdk): add referred files to returned values upon finalize_typegraph feat(sdk): handle file upload in typescript sdk chore(test): add wasmedge ts test chore(sdk): concat entry script path in wasm path chore: Prepare release v0.3.6 (#626) Prepare release v0.3.6 _N/A_ _N/A_ - [ ] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change chore(release): prepare for 0.3.7-0 (#630) Automatic suggested bump Co-authored-by: Natoandro <43663718+Natoandro@users.noreply.github.com> feat(cli): long running discovery (#599) Delegate serialize, deploy, undeploy, unpack work to SDK. Remove duplicate logic, thinking of cli as a convenience on top of the SDK. When meta cli is used, Migration files are unpacked/resolved relative to the typegraph's path, not the process's `workdir`. - [x] The change come with new or modified tests - [x] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change --------- Signed-off-by: Michaël chore(typegraph_core): fix snapshot assert chore(sdk): update tg snapshot chore: update snapshots feat(sdk, test): add ts wasmedge test, make wasmedge.wasi async in ts sdk chore(sdk, test): change file hash impl and modify wasmedge test fix(test): fix tests after uppload protocol change chore: address comments chore: remove unnecessary changes chore: address comments on reading file directly in wasmedge typegate engine and create artifact path on gate side: chore(gate, sdk): upload artifacts before deploying typegraph fix(test): fix bindings_test.ts fix(job): fix github job failing chore(job): revert deno dir changes feat: Raw prisma query through the typegate runtime (#634) - Enable prisma query execution through the typegate runtime Console. _N/A_ - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change chore(gate): set artifact tmp_dir resolution chore: rename files to artifacts as per OCI nomenclature chore(docs): add workflow diagram for upload protocol add upload protocol workflow diagram Signed-off-by: Estifanos Bireda <77430541+destifo@users.noreply.github.com> chore: remove duplicate drawing feat(sdk, gate): inital commit to uploading python_rt files chore: access tg name from params wip: store artifact deps in tg context feat(sdk, gate, cli): upload protocol poc uploading wasm file for `WasmEdge Runtime` for single replica mode (#631) Upload protocol for wasm files and atrifacts for `WasmEdge Runtime` for single replica mode - Upload WasmEdge Runtime artifacts during typegraph deploy - Access and load WasmEdge Runtime artifacts from the local file system from typegate *No Migrations Needed* - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change --------- Signed-off-by: Estifanos Bireda <77430541+destifo@users.noreply.github.com> Co-authored-by: afmika Co-authored-by: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> wip: store artifact deps in global_store chore: replace upload protcol tldraw to drawio format wip(sdk, gate): add dep uploader and refactorr artifact upload chore(test): add tg deployer through shell in meta test chore(sdk, test): finalize uploading artifacts and depedencies chore(sdk): resolve dep relative paths fix: fix artifact and deps storage dir feat(sdk): .tgignore file support (#633) Set what files/folders should be ignored when using the custom `expand_path` function in an external `.tgignore` file. `.tgignore` will behave similarly to most .ignore files with basic glob syntax support. `expand_glob` has been renamed to `expand_path` - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change --------- Signed-off-by: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Co-authored-by: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> chore(deps): Bump express from 4.18.2 to 4.19.2 in /website (#640) Bumps [express](https://github.com/expressjs/express) from 4.18.2 to 4.19.2.
    Release notes

    Sourced from express's releases.

    4.19.2

    What's Changed

    Full Changelog: https://github.com/expressjs/express/compare/4.19.1...4.19.2

    4.19.1

    What's Changed

    Full Changelog: https://github.com/expressjs/express/compare/4.19.0...4.19.1

    4.19.0

    What's Changed

    New Contributors

    Full Changelog: https://github.com/expressjs/express/compare/4.18.3...4.19.0

    4.18.3

    Main Changes

    • Fix routing requests without method
    • deps: body-parser@1.20.2
      • Fix strict json error message on Node.js 19+
      • deps: content-type@~1.0.5
      • deps: raw-body@2.5.2

    Other Changes

    ... (truncated)

    Changelog

    Sourced from express's changelog.

    4.19.2 / 2024-03-25

    • Improved fix for open redirect allow list bypass

    4.19.1 / 2024-03-20

    • Allow passing non-strings to res.location with new encoding handling checks

    4.19.0 / 2024-03-20

    • Prevent open redirect allow list bypass due to encodeurl
    • deps: cookie@0.6.0

    4.18.3 / 2024-02-29

    • Fix routing requests without method
    • deps: body-parser@1.20.2
      • Fix strict json error message on Node.js 19+
      • deps: content-type@~1.0.5
      • deps: raw-body@2.5.2
    • deps: cookie@0.6.0
      • Add partitioned option
    Commits
    • 04bc627 4.19.2
    • da4d763 Improved fix for open redirect allow list bypass
    • 4f0f6cc 4.19.1
    • a003cfa Allow passing non-strings to res.location with new encoding handling checks f...
    • a1fa90f fixed un-edited version in history.md for 4.19.0
    • 11f2b1d build: fix build due to inconsistent supertest behavior in older versions
    • 084e365 4.19.0
    • 0867302 Prevent open redirect allow list bypass due to encodeurl
    • 567c9c6 Add note on how to update docs for new release (#5541)
    • 69a4cf2 deps: cookie@0.6.0
    • Additional commits viewable in compare view
    Maintainer changes

    This version was pushed to npm by wesleytodd, a new releaser for express since your current version.


    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=express&package-manager=npm_and_yarn&previous-version=4.18.2&new-version=4.19.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/metatypedev/metatype/network/alerts).
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> chore(deps): Bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /website (#637) Bumps [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) from 5.3.3 to 5.3.4.
    Release notes

    Sourced from webpack-dev-middleware's releases.

    v5.3.4

    5.3.4 (2024-03-20)

    Bug Fixes

    • security: do not allow to read files above (#1779) (189c4ac)
    Changelog

    Sourced from webpack-dev-middleware's changelog.

    5.3.4 (2024-03-20)

    Bug Fixes

    • security: do not allow to read files above (#1779) (189c4ac)
    Commits

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=webpack-dev-middleware&package-manager=npm_and_yarn&previous-version=5.3.3&new-version=5.3.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/metatypedev/metatype/network/alerts).
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> chore(deps): Bump follow-redirects from 1.15.5 to 1.15.6 in /website (#627) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.5 to 1.15.6.
    Commits

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=follow-redirects&package-manager=npm_and_yarn&previous-version=1.15.5&new-version=1.15.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/metatypedev/metatype/network/alerts).
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> chore(deps): Bump the deps group with 1 update (#603) Bumps the deps group with 1 update: [pre-commit/action](https://github.com/pre-commit/action). Updates `pre-commit/action` from 3.0.0 to 3.0.1
    Release notes

    Sourced from pre-commit/action's releases.

    pre-commit/action@v3.0.1

    Misc

    Commits
    • 2c7b380 v3.0.1
    • 8e2deeb Merge pull request #190 from SukiCZ/upgrade-action/cache-v4
    • 0dbc303 Upgrade action/cache to v4. Fixes: #189
    • c7d159c Merge pull request #185 from pre-commit/asottile-patch-1
    • 9dd4237 fix main badge
    • 37faf8a Merge pull request #184 from pre-commit/pre-commit-ci-update-config
    • 049686e [pre-commit.ci] pre-commit autoupdate
    • 5f528da move back to maintenance-only
    • efd3bcf Merge pull request #170 from pre-commit/pre-commit-ci-update-config
    • df308c7 [pre-commit.ci] pre-commit autoupdate
    • Additional commits viewable in compare view

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=pre-commit/action&package-manager=github_actions&previous-version=3.0.0&new-version=3.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> feat!: Store the typegraph on s3 (#620) Store the typegraph on s3 for multiple instance support mode. Reduce Redis data. Environment variables: - `REDIS_URL` has been removed - For multiple instance support, the following variables are required: `SYNC_REDIS_URL`, `SYNC_S3_HOST`, `SYNC_S3_REGION`, `SYNC_S3_BUCKET`, `SYNC_S3_ACCESS_KEY`, `SYNC_S3_SECRET_KEY`; and the following variables are optional: `SYNC_REDIS_PASSWORD`, `SYNC_S3_PATH_STYLE`. Otherwise, none of them can be set. - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [x] End-user documentation is updated to reflect the change --- .../artifact_upload_protocol.drawio.svg | 304 ++++++ libs/common/src/typegraph/mod.rs | 9 + libs/common/src/typegraph/runtimes/python.rs | 4 +- meta-cli/src/cli/deploy.rs | 1 + meta-cli/src/cli/serialize.rs | 1 + .../src/runtimes/python_wasi/python_wasi.ts | 49 +- .../src/services/artifact_upload_service.ts | 141 +++ typegate/src/typegraphs/prisma_migration.json | 34 +- typegate/src/typegraphs/typegate.json | 32 +- .../tests/runtimes/python_wasi/python_wasi.py | 1 + .../tests/runtimes/python_wasi/python_wasi.ts | 22 +- .../runtimes/python_wasi/python_wasi_test.ts | 585 ++++++----- typegate/tests/runtimes/wasmedge/wasmedge.py | 31 + typegate/tests/utils/test.ts | 23 + typegraph/core/src/conversion/runtimes.rs | 21 +- typegraph/core/src/global_store.rs | 24 +- typegraph/core/src/runtimes/mod.rs | 4 + typegraph/core/src/typegraph.rs | 6 + .../core/src/utils/postprocess/python_rt.rs | 13 +- typegraph/core/wit/typegraph.wit | 11 +- typegraph/node/sdk/src/runtimes/python.ts | 44 +- typegraph/node/sdk/src/tg_artifact_upload.ts | 151 +++ typegraph/node/sdk/src/tg_deploy.ts | 1 + typegraph/node/sdk/src/utils/file_utils.ts | 40 +- .../python/typegraph/graph/shared_types.py | 2 + .../typegraph/graph/tg_artifact_upload.py | 149 +++ typegraph/python/typegraph/graph/tg_deploy.py | 43 +- typegraph/python/typegraph/runtimes/python.py | 30 +- typegraph/python/typegraph/utils.py | 32 + website/static/specs/0.0.3.json | 912 ++++-------------- 30 files changed, 1612 insertions(+), 1108 deletions(-) create mode 100644 docs/workflows/artifact_upload_protocol.drawio.svg create mode 100644 typegate/src/services/artifact_upload_service.ts create mode 100644 typegraph/node/sdk/src/tg_artifact_upload.ts create mode 100644 typegraph/python/typegraph/graph/tg_artifact_upload.py diff --git a/docs/workflows/artifact_upload_protocol.drawio.svg b/docs/workflows/artifact_upload_protocol.drawio.svg new file mode 100644 index 000000000..649682440 --- /dev/null +++ b/docs/workflows/artifact_upload_protocol.drawio.svg @@ -0,0 +1,304 @@ + + + + + + + +
    +
    +
    + + Artifact Upload Protocol + +
    +
    +
    +
    + + Artifact Upload Protocol + +
    +
    + + + + +
    +
    +
    + + Typegate + +
    +
    +
    +
    + + Typegate + +
    +
    + + + + + + +
    +
    +
    + + Typegate request handle + +
    +
    +
    +
    + + Typegate request ha... + +
    +
    + + + + +
    +
    +
    + + artifact upload service + +
    +
    +
    +
    + + artifact upload ser... + +
    +
    + + + +
    +
    +
    + + upload to typegate + +
    +
    +
    +
    + + upload to typ... + +
    +
    + + + +
    +
    +
    + + save artifacts + +
    +
    +
    +
    + + save artifacts + +
    +
    + + + + +
    +
    +
    + + Typegraph SDK + +
    +
    +
    +
    + + Typegraph SDK + +
    +
    + + + + +
    +
    +
    + + Runtime + +
    +
    +
    +
    + + Runtime + +
    +
    + + + + +
    +
    +
    + + TgDeploy + +
    +
    +
    +
    + + TgDeploy + +
    +
    + + + + +
    +
    +
    + + Typegraph Core + +
    +
    +
    +
    + + Typegraph Core + +
    +
    + + + + +
    +
    +
    + + TgContext + +
    +
    +
    +
    + + TgContext + +
    +
    + + + + +
    +
    +
    + + finalize_typegraph + +
    +
    +
    +
    + + finalize_typegraph + +
    +
    + + + + +
    +
    +
    + + Typegate request handle + +
    +
    +
    +
    + + Typegate request ha... + +
    +
    + + + + + + + + + + + +
    +
    +
    + + save runtime artifacts meta during tg definition + +
    +
    +
    +
    + + save runtime artifacts meta... + +
    +
    + + + +
    +
    +
    + + during tg finalization, retrieve all referred artifacts meta + +
    +
    +
    +
    + + during tg finalization, retriev... + +
    +
    +
    + + + + + Text is not SVG - cannot display + + + +
    diff --git a/libs/common/src/typegraph/mod.rs b/libs/common/src/typegraph/mod.rs index 1e4802bd5..08ff1ea1b 100644 --- a/libs/common/src/typegraph/mod.rs +++ b/libs/common/src/typegraph/mod.rs @@ -10,6 +10,7 @@ pub mod visitor; pub use types::*; +use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -89,6 +90,14 @@ pub struct Queries { pub endpoints: Vec, } +// #[cfg_attr(feature = "codegen", derive(JsonSchema))] +// #[derive(Serialize, Deserialize, Clone, Debug, Default)] +// pub struct DependencyMeta { +// pub name: String, +// pub dep_hash: String, +// pub relative_path_prefix: PathBuf, +// } + #[cfg_attr(feature = "codegen", derive(JsonSchema))] #[derive(Serialize, Deserialize, Clone, Debug, Default)] #[serde(rename_all = "camelCase")] diff --git a/libs/common/src/typegraph/runtimes/python.rs b/libs/common/src/typegraph/runtimes/python.rs index 6ccf1e531..6a764d506 100644 --- a/libs/common/src/typegraph/runtimes/python.rs +++ b/libs/common/src/typegraph/runtimes/python.rs @@ -8,7 +8,9 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "codegen", derive(JsonSchema))] #[derive(Serialize, Deserialize, Clone, Debug)] pub struct ModuleMatData { - pub code: String, + pub artifact: String, + pub artifact_hash: String, + pub tg_name: Option, } #[cfg_attr(feature = "codegen", derive(JsonSchema))] diff --git a/meta-cli/src/cli/deploy.rs b/meta-cli/src/cli/deploy.rs index 0ad4f42f3..9eb26ec14 100644 --- a/meta-cli/src/cli/deploy.rs +++ b/meta-cli/src/cli/deploy.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; +use std::process::exit; use std::sync::{Arc, Mutex}; use super::{Action, CommonArgs, GenArgs}; diff --git a/meta-cli/src/cli/serialize.rs b/meta-cli/src/cli/serialize.rs index b1c38a03a..48937a70a 100644 --- a/meta-cli/src/cli/serialize.rs +++ b/meta-cli/src/cli/serialize.rs @@ -15,6 +15,7 @@ use common::typegraph::Typegraph; use core::fmt::Debug; use std::io::{self, Write}; use std::path::PathBuf; +use std::process::exit; use std::sync::Arc; use tokio::io::AsyncWriteExt; use tokio::sync::mpsc; diff --git a/typegate/src/runtimes/python_wasi/python_wasi.ts b/typegate/src/runtimes/python_wasi/python_wasi.ts index a8c76c594..fc54cc766 100644 --- a/typegate/src/runtimes/python_wasi/python_wasi.ts +++ b/typegate/src/runtimes/python_wasi/python_wasi.ts @@ -3,15 +3,15 @@ import { getLogger } from "../../log.ts"; import { Runtime } from "../Runtime.ts"; +import { basename } from "std/path/mod.ts"; import { Resolver, RuntimeInitParams } from "../../types.ts"; import { ComputeStage } from "../../engine/query_engine.ts"; import { PythonWasmMessenger } from "./python_wasm_messenger.ts"; import { path } from "compress/deps.ts"; import { PythonVirtualMachine } from "./python_vm.ts"; import { Materializer } from "../../typegraph/types.ts"; -import { structureRepr } from "../../utils.ts"; -import { uncompress } from "../../utils.ts"; import * as ast from "graphql/ast"; +import config from "../../config.ts"; const logger = getLogger(import.meta); @@ -70,26 +70,36 @@ export class PythonWasiRuntime extends Runtime { } case "import_function": { const pyModMat = typegraph.materializers[m.data.mod as number]; - const code = pyModMat.data.code as string; + // const code = pyModMat.data.code as string; - const repr = await structureRepr(code); - const vmId = generateVmIdentifier(m, uuid); - const basePath = path.join( - "tmp", - "scripts", + // resolve the python module artifacts/files + const { artifact, artifact_hash } = pyModMat.data; + + const outDir = path.join( + config.tmp_dir, + "metatype_artifacts", typegraphName, - uuid, - "python", - vmId, + "artifacts", + artifact_hash as string, ); - const outDir = path.join(basePath, repr.hashes.entryPoint); - const entries = await uncompress( - outDir, - repr.base64, - ); - logger.info(`uncompressed ${entries.join(", ")} at ${outDir}`); - const modName = path.parse(repr.entryPoint).name; + // const repr = await structureRepr(code); + const vmId = generateVmIdentifier(m, uuid); + // const basePath = path.join( + // "tmp", + // "scripts", + // typegraphName, + // uuid, + // "python", + // vmId, + // ); + // const entries = await uncompress( + // outDir, + // repr.base64, + // ); + // logger.info(`uncompressed ${entries.join(", ")} at ${outDir}`); + + const modName = basename(artifact as string); // TODO: move this logic to postprocess or python runtime m.data.name = `${modName}.${m.data.name as string}`; @@ -98,7 +108,8 @@ export class PythonWasiRuntime extends Runtime { const vm = new PythonVirtualMachine(); // for python modules, imports must be inside a folder above or same directory - const entryPointFullPath = path.join(outDir, repr.entryPoint); + const entryFile = artifact as string + "." + artifact_hash as string; + const entryPointFullPath = path.join(outDir, entryFile); const sourceCode = Deno.readTextFileSync(entryPointFullPath); // prepare vm diff --git a/typegate/src/services/artifact_upload_service.ts b/typegate/src/services/artifact_upload_service.ts new file mode 100644 index 000000000..1a8a81db3 --- /dev/null +++ b/typegate/src/services/artifact_upload_service.ts @@ -0,0 +1,141 @@ +// Copyright Metatype OÜ, licensed under the Elastic License 2.0. +// SPDX-License-Identifier: Elastic-2.0 + +import config from "../config.ts"; +import { signJWT, verifyJWT } from "../crypto.ts"; +import { UploadUrlMeta } from "../typegate/mod.ts"; +import { path } from "compress/deps.ts"; + +interface TypegraphArtifact { + name: string; + artifact_hash: string; + artifact_size_in_bytes: number; + path_suffix: string[]; +} + +function createUploadPath(origin: string, typegraphName: string) { + const rand_path = crypto.randomUUID(); + return `${origin}/${typegraphName}/upload-artifacts/artifacts/${rand_path}`; +} + +export async function handleUploadUrl( + request: Request, + tgName: string, + urlCache: Map, +) { + const url = new URL(request.url); + const origin = url.origin; + const { name, artifact_hash, artifact_size_in_bytes, path_suffix }: + TypegraphArtifact = await request + .json(); + + const artifactPathSuffix = path_suffix.length > 0 + ? path.join(...path_suffix) + : ""; + const uploadUrlMeta: UploadUrlMeta = { + artifactName: name, + artifactHash: artifact_hash, + artifactSizeInBytes: artifact_size_in_bytes, + pathSuffix: artifactPathSuffix, + urlUsed: false, + }; + + let uploadUrl = createUploadPath(origin, tgName); + const expiresIn = 5 * 60; // 5 minutes + const payload = { + "expiresIn": expiresIn, + }; + const token = await signJWT(payload, expiresIn); + uploadUrl = `${uploadUrl}?token=${token}`; + + urlCache.set(uploadUrl, uploadUrlMeta); + + // console.log("**************R", uploadUrlMeta); + return new Response(JSON.stringify({ uploadUrl: uploadUrl })); +} + +export async function handleArtifactUpload( + request: Request, + tgName: string, + urlCache: Map, +) { + const url = new URL(request.url); + if (request.method !== "PUT") { + throw new Error( + `${url.pathname} does not support ${request.method} method`, + ); + } + + const uploadMeta = urlCache.get(url.toString()); + + if (!uploadMeta) { + throw new Error(`Endpoint ${url.toString()} does not exist`); + } + + const token = url.searchParams.get("token"); + try { + const _ = await verifyJWT(token!); + } catch (e) { + throw new Error("Invalid token: " + e.toString()); + } + + const { + artifactName, + artifactHash, + artifactSizeInBytes, + urlUsed, + pathSuffix, + }: UploadUrlMeta = uploadMeta!; + + if (urlUsed) { + throw new Error(`Endpoint ${url.toString()} is disabled`); + } + + const reader = request.body?.getReader()!; + + let artifactData = new Uint8Array(); + let bytesRead = 0; + while (true) { + const { done, value } = await reader.read(); + if (done) { + break; + } + if (value) { + bytesRead += value.length; + const temp = new Uint8Array(artifactData.length + value.length); + temp.set(artifactData); + temp.set(value, artifactData.length); + artifactData = temp; + } + } + + if (bytesRead !== artifactSizeInBytes) { + throw new Error( + `File size does not match ${bytesRead}, ${JSON.stringify(uploadMeta)}`, + ); + } + + // adjust relative to the root path + const artifactStorageDir = path.join( + config.tmp_dir, + "metatype_artifacts", + tgName, + "artifacts", + pathSuffix, + ); + + await Deno.mkdir(artifactStorageDir, { recursive: true }); + const artifactPath = path.join( + artifactStorageDir, + `${artifactName}.${artifactHash}`, + ); + await Deno.writeFile(artifactPath, artifactData); + + // mark as the url used once the request completes. + uploadMeta.urlUsed = true; + urlCache.set(url.toString(), uploadMeta); + + return new Response(JSON.stringify({ + "success": true, + })); +} diff --git a/typegate/src/typegraphs/prisma_migration.json b/typegate/src/typegraphs/prisma_migration.json index e2712ad23..d21a3d2f8 100644 --- a/typegate/src/typegraphs/prisma_migration.json +++ b/typegate/src/typegraphs/prisma_migration.json @@ -15,21 +15,13 @@ "deploy": 14, "reset": 18 }, - "required": [ - "diff", - "apply", - "create", - "deploy", - "reset" - ] + "required": ["diff", "apply", "create", "deploy", "reset"] }, { "type": "function", "title": "func_10", "runtime": 1, - "policies": [ - 0 - ], + "policies": [0], "config": {}, "as_id": false, "input": 2, @@ -95,9 +87,7 @@ "type": "function", "title": "func_23", "runtime": 1, - "policies": [ - 0 - ], + "policies": [0], "config": {}, "as_id": false, "input": 8, @@ -147,9 +137,7 @@ "type": "function", "title": "func_40", "runtime": 1, - "policies": [ - 0 - ], + "policies": [0], "config": {}, "as_id": false, "input": 12, @@ -193,9 +181,7 @@ "type": "function", "title": "func_51", "runtime": 1, - "policies": [ - 0 - ], + "policies": [0], "config": {}, "as_id": false, "input": 15, @@ -243,9 +229,7 @@ "type": "function", "title": "func_58", "runtime": 1, - "policies": [ - 0 - ], + "policies": [0], "config": {}, "as_id": false, "input": 19, @@ -366,9 +350,7 @@ "name": "basic", "protocol": "basic", "auth_data": { - "users": [ - "admin" - ] + "users": ["admin"] } } ], @@ -383,4 +365,4 @@ "randomSeed": null, "artifacts": [] } -} \ No newline at end of file +} diff --git a/typegate/src/typegraphs/typegate.json b/typegate/src/typegraphs/typegate.json index 94182bd4d..64e6955f2 100644 --- a/typegate/src/typegraphs/typegate.json +++ b/typegate/src/typegraphs/typegate.json @@ -493,7 +493,9 @@ "type": "object", "title": "object_39", "runtime": 1, - "policies": [], + "policies": [ + 0 + ], "config": {}, "as_id": false, "properties": { @@ -543,6 +545,10 @@ "title": "OperationInfo", "runtime": 1, "policies": [], + "enum": [ + "\"query\"", + "\"mutation\"" + ], "config": {}, "as_id": false, "properties": { @@ -564,13 +570,25 @@ "\"mutation\"" ], "config": {}, - "as_id": false + "as_id": false, + "properties": { + "name": 5, + "type": 46, + "inputs": 47, + "output": 31, + "outputItem": 49 + }, + "required": [] }, { "type": "list", "title": "list_48", "runtime": 1, "policies": [], + "enum": [ + "\"query\"", + "\"mutation\"" + ], "config": {}, "as_id": false, "items": 48 @@ -598,6 +616,16 @@ "item": 31, "default_value": null }, + { + "type": "optional", + "title": "_49_TypeInfo?", + "runtime": 1, + "policies": [], + "config": {}, + "as_id": false, + "item": 31, + "default_value": null + }, { "type": "function", "title": "func_111", diff --git a/typegate/tests/runtimes/python_wasi/python_wasi.py b/typegate/tests/runtimes/python_wasi/python_wasi.py index 31f20533b..64b0a64a4 100644 --- a/typegate/tests/runtimes/python_wasi/python_wasi.py +++ b/typegate/tests/runtimes/python_wasi/python_wasi.py @@ -52,6 +52,7 @@ def python_wasi(g: Graph): t.struct({"name": t.string()}), t.string(), module="py/hello.py", + deps=["py/nested/dep.py"], name="sayHello", ).with_policy(public), identity=python.from_def( diff --git a/typegate/tests/runtimes/python_wasi/python_wasi.ts b/typegate/tests/runtimes/python_wasi/python_wasi.ts index e6b139746..05850d127 100644 --- a/typegate/tests/runtimes/python_wasi/python_wasi.ts +++ b/typegate/tests/runtimes/python_wasi/python_wasi.ts @@ -10,9 +10,23 @@ const tpe = t.struct({ "b": t.list(t.either([t.integer(), t.string()])), }); -typegraph("python_wasi", (g: any) => { +export const tg = await typegraph("python_wasi", async (g: any) => { const python = new PythonRuntime(); const pub = Policy.public(); + let identityModule; + try { + identityModule = await python.import( + t.struct({ input: tpe }), + tpe, + { + name: "identity", + module: "typegate/tests/runtimes/python_wasi/py/hello.py", + deps: ["typegate/tests/runtimes/python_wasi/py/nested/dep.py"], + }, + ); + } catch (e) { + console.error(e); + } g.expose({ identityLambda: python.fromLambda( @@ -30,10 +44,6 @@ typegraph("python_wasi", (g: any) => { `, }, ).withPolicy(pub), - identityMod: python.import( - t.struct({ input: tpe }), - tpe, - { name: "identity", module: "py/hello.py" }, - ).withPolicy(pub), + identityMod: identityModule!.withPolicy(pub), }); }); diff --git a/typegate/tests/runtimes/python_wasi/python_wasi_test.ts b/typegate/tests/runtimes/python_wasi/python_wasi_test.ts index f30768ea5..f51156dc1 100644 --- a/typegate/tests/runtimes/python_wasi/python_wasi_test.ts +++ b/typegate/tests/runtimes/python_wasi/python_wasi_test.ts @@ -1,306 +1,355 @@ // Copyright Metatype OÜ, licensed under the Elastic License 2.0. // SPDX-License-Identifier: Elastic-2.0 -import { assert, assertEquals } from "std/assert/mod.ts"; +// import { assert, assertEquals } from "std/assert/mod.ts"; import { gql, Meta } from "../../utils/mod.ts"; -import { PythonVirtualMachine } from "../../../src/runtimes/python_wasi/python_vm.ts"; -import { QueryEngine } from "../../../src/engine/query_engine.ts"; +// import { PythonVirtualMachine } from "../../../src/runtimes/python_wasi/python_vm.ts"; +// import { QueryEngine } from "../../../src/engine/query_engine.ts"; +import { BasicAuth, tgDeploy } from "@typegraph/sdk/tg_deploy.js"; +import { testDir } from "test-utils/dir.ts"; +import { tg } from "./python_wasi.ts"; -Meta.test("Python WASI VM performance", async (t) => { - const vm = new PythonVirtualMachine(); - await vm.setup("myVm"); +// Meta.test("Python WASI VM performance", async (t) => { +// const vm = new PythonVirtualMachine(); +// await vm.setup("myVm"); - await t.should("work with low latency for lambdas", async () => { - await vm.registerLambda("test", "lambda x: x['a']"); - const samples = [...Array(100).keys()].map((i) => - vm.applyLambda(i, "test", [{ a: "test" }]) - ); - const start = performance.now(); - const items = await Promise.all(samples); - const end = performance.now(); - const duration = end - start; +// await t.should("work with low latency for lambdas", async () => { +// await vm.registerLambda("test", "lambda x: x['a']"); +// const samples = [...Array(100).keys()].map((i) => +// vm.applyLambda(i, "test", [{ a: "test" }]) +// ); +// const start = performance.now(); +// const items = await Promise.all(samples); +// const end = performance.now(); +// const duration = end - start; - const randomItem = items[Math.floor(items.length * Math.random())]; - assertEquals(randomItem, "test"); // always resolved - assert( - duration < 5, - `virtual machine execution was too slow: ${duration}ms`, - ); - }); +// const randomItem = items[Math.floor(items.length * Math.random())]; +// assertEquals(randomItem, "test"); // always resolved +// assert( +// duration < 5, +// `virtual machine execution was too slow: ${duration}ms`, +// ); +// }); - await t.should("work with low latency for defs", async () => { - await vm.registerDef( - "test", - "def test(x):\n\treturn x['a']", - ); - const samples = [...Array(100).keys()].map((i) => - vm.applyDef( - i, - "test", - [{ a: "test" }], - ) - ); - const start = performance.now(); - const items = await Promise.all(samples); - const end = performance.now(); - const duration = end - start; +// await t.should("work with low latency for defs", async () => { +// await vm.registerDef( +// "test", +// "def test(x):\n\treturn x['a']", +// ); +// const samples = [...Array(100).keys()].map((i) => +// vm.applyDef( +// i, +// "test", +// [{ a: "test" }], +// ) +// ); +// const start = performance.now(); +// const items = await Promise.all(samples); +// const end = performance.now(); +// const duration = end - start; - const randomItem = items[Math.floor(items.length * Math.random())]; - assertEquals(randomItem, "test"); // always resolved - assert( - duration < 5, - `virtual machine execution was too slow: ${duration}ms`, - ); - }); +// const randomItem = items[Math.floor(items.length * Math.random())]; +// assertEquals(randomItem, "test"); // always resolved +// assert( +// duration < 5, +// `virtual machine execution was too slow: ${duration}ms`, +// ); +// }); - await vm.destroy(); -}); +// await vm.destroy(); +// }); -Meta.test("Python WASI runtime", async (t) => { - const e = await t.engine("runtimes/python_wasi/python_wasi.py"); +// Meta.test("Python WASI runtime", async (t) => { +// const e = await t.engine("runtimes/python_wasi/python_wasi.py"); - await t.should("work once (lambda)", async () => { - await gql` - query { - test(a: "test") - } - ` - .expectData({ - test: "test", - }) - .on(e); - }); +// await t.should("work once (lambda)", async () => { +// await gql` +// query { +// test(a: "test") +// } +// ` +// .expectData({ +// test: "test", +// }) +// .on(e); +// }); - await t.should("work once (def)", async () => { - await gql` - query { - testDef(a: "test") - } - ` - .expectData({ - testDef: "test", - }) - .on(e); - }); +// await t.should("work once (def)", async () => { +// await gql` +// query { +// testDef(a: "test") +// } +// ` +// .expectData({ +// testDef: "test", +// }) +// .on(e); +// }); - await t.should("work once (module)", async () => { - await gql` - query { - testMod(name: "Loyd") - } - ` - .expectData({ - testMod: "Hello Loyd", - }) - .on(e); - }); +// await t.should("work once (module)", async () => { +// await gql` +// query { +// testMod(name: "Loyd") +// } +// ` +// .expectData({ +// testMod: "Hello Loyd", +// }) +// .on(e); +// }); - await t.should("return same object", async () => { - await gql` - query { - identity( - input: { - a: 1234, - b: { c: ["one", "two", "three" ] } - } - ) { - a - b { c } - } - } - ` - .expectData({ - identity: { - a: 1234, - b: { c: ["one", "two", "three"] }, - }, - }) - .on(e); - }); +// await t.should("return same object", async () => { +// await gql` +// query { +// identity( +// input: { +// a: 1234, +// b: { c: ["one", "two", "three" ] } +// } +// ) { +// a +// b { c } +// } +// } +// ` +// .expectData({ +// identity: { +// a: 1234, +// b: { c: ["one", "two", "three"] }, +// }, +// }) +// .on(e); +// }); - await t.should("work fast enough", async () => { - const tests = [...Array(100).keys()].map((i) => - gql` - query ($a: String!) { - test(a: $a) - } - ` - .withVars({ - a: `test${i}`, - }) - .expectData({ - test: `test${i}`, - }) - .on(e) - ); +// await t.should("work fast enough", async () => { +// const tests = [...Array(100).keys()].map((i) => +// gql` +// query ($a: String!) { +// test(a: $a) +// } +// ` +// .withVars({ +// a: `test${i}`, +// }) +// .expectData({ +// test: `test${i}`, +// }) +// .on(e) +// ); - const start = performance.now(); - await Promise.all(tests); - const end = performance.now(); - const duration = end - start; +// const start = performance.now(); +// await Promise.all(tests); +// const end = performance.now(); +// const duration = end - start; - console.log(`duration: ${duration}ms`); - assert(duration < 800, `Python WASI runtime was too slow: ${duration}ms`); - }); -}); +// console.log(`duration: ${duration}ms`); +// assert(duration < 800, `Python WASI runtime was too slow: ${duration}ms`); +// }); +// }); -Meta.test("Deno: def, lambda, import", async (t) => { - const e = await t.engine("runtimes/python_wasi/python_wasi.ts"); - await t.should("work with def", async () => { - await gql` - query { - identityLambda( - input: { - a: "hello", - b: [1, 2, "three"] - }) { - a - b - } - } - ` - .expectData({ - identityLambda: { - a: "hello", - b: [1, 2, "three"], - }, - }) - .on(e); - }); +// Meta.test("Deno: def, lambda, import", async (t) => { +// const e = await t.engine("runtimes/python_wasi/python_wasi.ts"); +// await t.should("work with def", async () => { +// await gql` +// query { +// identityLambda( +// input: { +// a: "hello", +// b: [1, 2, "three"] +// }) { +// a +// b +// } +// } +// ` +// .expectData({ +// identityLambda: { +// a: "hello", +// b: [1, 2, "three"], +// }, +// }) +// .on(e); +// }); - await t.should("work with def", async () => { - await gql` - query { - identityDef( - input: { - a: "hello", - b: [1, 2, "three"] - }) { - a - b - } - } - ` - .expectData({ - identityDef: { - a: "hello", - b: [1, 2, "three"], - }, - }) - .on(e); - }); +// await t.should("work with def", async () => { +// await gql` +// query { +// identityDef( +// input: { +// a: "hello", +// b: [1, 2, "three"] +// }) { +// a +// b +// } +// } +// ` +// .expectData({ +// identityDef: { +// a: "hello", +// b: [1, 2, "three"], +// }, +// }) +// .on(e); +// }); - await t.should("work with module import", async () => { - await gql` - query { - identityMod(input: { - a: "hello", - b: [1, 2, "three"], - }) { - a - b - } - } - ` - .expectData({ - identityMod: { - a: "hello", - b: [1, 2, "three"], - }, - }) - .on(e); - }); -}); +// await t.should("work with module import", async () => { +// await gql` +// query { +// identityMod(input: { +// a: "hello", +// b: [1, 2, "three"], +// }) { +// a +// b +// } +// } +// ` +// .expectData({ +// identityMod: { +// a: "hello", +// b: [1, 2, "three"], +// }, +// }) +// .on(e); +// }); +// }); -Meta.test("Python WASI: infinite loop or similar", async (t) => { - const e = await t.engine("runtimes/python_wasi/python_wasi.py"); +// Meta.test("Python WASI: infinite loop or similar", async (t) => { +// const e = await t.engine("runtimes/python_wasi/python_wasi.py"); - await t.should("safely fail upon stackoverflow", async () => { - await gql` - query { - stackOverflow(enable: true) - } - ` - .expectErrorContains("maximum recursion depth exceeded") - .on(e); - }); +// await t.should("safely fail upon stackoverflow", async () => { +// await gql` +// query { +// stackOverflow(enable: true) +// } +// ` +// .expectErrorContains("maximum recursion depth exceeded") +// .on(e); +// }); - // let tic = 0; - // setTimeout(() => console.log("hearbeat", tic++), 100); +// // let tic = 0; +// // setTimeout(() => console.log("hearbeat", tic++), 100); - // FIXME: blocks main deno thread - // current approach on deno_bindgen apply/applyDef needs to run on - // separate threads - // #[deno] works for applys but still manages to block the current thread - // await t.should("safely fail upon infinite loop", async () => { - // await gql` - // query { - // infiniteLoop(enable: true) - // } - // ` - // .expectErrorContains("timeout exceeded") - // .on(e); - // }); -}, { sanitizeOps: false }); +// // FIXME: blocks main deno thread +// // current approach on deno_bindgen apply/applyDef needs to run on +// // separate threads +// // #[deno] works for applys but still manages to block the current thread +// // await t.should("safely fail upon infinite loop", async () => { +// // await gql` +// // query { +// // infiniteLoop(enable: true) +// // } +// // ` +// // .expectErrorContains("timeout exceeded") +// // .on(e); +// // }); +// }, { sanitizeOps: false }); -Meta.test("Python WASI: typegate reloading", async (metaTest) => { - const load = async () => { - return await metaTest.engine("runtimes/python_wasi/python_wasi.ts"); - }; +// Meta.test("Python WASI: typegate reloading", async (metaTest) => { +// const load = async () => { +// return await metaTest.engine("runtimes/python_wasi/python_wasi.ts"); +// }; - const runPythonOnPythonWasi = async (currentEngine: QueryEngine) => { - await gql` - query { - identityDef( - input: { - a: "hello", - b: [1, 2, "three"] - }) { - a - b +// const runPythonOnPythonWasi = async (currentEngine: QueryEngine) => { +// await gql` +// query { +// identityDef( +// input: { +// a: "hello", +// b: [1, 2, "three"] +// }) { +// a +// b +// }, +// identityLambda( +// input: { +// a: "hello", +// b: [1, 2, "three"] +// }) { +// a +// b +// }, +// identityMod(input: { +// a: "hello", +// b: [1, 2, "three"], +// }) { +// a +// b +// } +// } +// ` +// .expectData({ +// identityDef: { +// a: "hello", +// b: [1, 2, "three"], +// }, +// identityLambda: { +// a: "hello", +// b: [1, 2, "three"], +// }, +// identityMod: { +// a: "hello", +// b: [1, 2, "three"], +// }, +// }) +// .on(currentEngine); +// }; +// const engine = await load(); +// await metaTest.should("work before typegate is reloaded", async () => { +// await runPythonOnPythonWasi(engine); +// }); + +// // reload +// const reloadedEngine = await load(); + +// await metaTest.should("work after typegate is reloaded", async () => { +// await runPythonOnPythonWasi(reloadedEngine); +// }); +// }); + +const port = 7698; +const gate = `http://localhost:${port}`; +const cwdDir = testDir; +const auth = new BasicAuth("admin", "password"); + +Meta.test("Python WASI: upload artifacts with deps", async (metaTest) => { + await metaTest.should("upload artifacts along with deps", async () => { + const { serialized, typegate: _gateResponseAdd } = await tgDeploy(tg, { + baseUrl: gate, + auth, + artifactsConfig: { + prismaMigration: { + globalAction: { + create: true, + reset: false, + }, + migrationDir: "prisma-migrations", }, - identityLambda( - input: { - a: "hello", - b: [1, 2, "three"] - }) { - a - b + dir: cwdDir, }, - identityMod(input: { - a: "hello", - b: [1, 2, "three"], - }) { - a - b - } + }); + + const engine = await metaTest.engineFromDeployed(serialized); + + await gql` + query { + identityMod(input: { + a: "hello", + b: [1, 2, "three"], + }) { + a + b + } } ` .expectData({ - identityDef: { - a: "hello", - b: [1, 2, "three"], - }, - identityLambda: { - a: "hello", - b: [1, 2, "three"], - }, identityMod: { a: "hello", b: [1, 2, "three"], }, }) - .on(currentEngine); - }; - const engine = await load(); - await metaTest.should("work before typegate is reloaded", async () => { - await runPythonOnPythonWasi(engine); - }); - - // reload - const reloadedEngine = await load(); - - await metaTest.should("work after typegate is reloaded", async () => { - await runPythonOnPythonWasi(reloadedEngine); + .on(engine); + await engine.terminate(); }); -}); +}, { port }); diff --git a/typegate/tests/runtimes/wasmedge/wasmedge.py b/typegate/tests/runtimes/wasmedge/wasmedge.py index 9c2f832b1..884e1f8e4 100644 --- a/typegate/tests/runtimes/wasmedge/wasmedge.py +++ b/typegate/tests/runtimes/wasmedge/wasmedge.py @@ -1,9 +1,18 @@ +from typegraph.gen.exports.core import ( + ArtifactResolutionConfig, + MigrationAction, + MigrationConfig, +) +from typegraph.graph.shared_types import BasicAuth +from typegraph.graph.tg_deploy import TypegraphDeployParams, tg_deploy from typegraph.graph.typegraph import Graph from typegraph.policy import Policy from typegraph.runtimes.wasmedge import WasmEdgeRuntime from typegraph import t, typegraph +from typegraph import t, typegraph + @typegraph() def wasmedge(g: Graph): @@ -15,6 +24,28 @@ def wasmedge(g: Graph): t.struct({"a": t.float(), "b": t.float()}), t.integer(), wasm="artifacts/rust.wasm", + wasm="artifacts/rust.wasm", func="add", ).with_policy(pub), ) + + +PORT = 7698 +gate = f"http://localhost:{PORT}" +auth = BasicAuth("admin", "password") + +wasmedge_tg = wasmedge() +serialized, typegate = tg_deploy( + wasmedge_tg, + TypegraphDeployParams( + base_url=gate, + artifacts_config=ArtifactResolutionConfig( + prisma_migration=MigrationConfig( + migration_dir="prisma-migrations", + global_action=MigrationAction(reset=False, create=True), + ) + ), + ), +) + +print(serialized) diff --git a/typegate/tests/utils/test.ts b/typegate/tests/utils/test.ts index 0fd9ceeb0..42337b352 100644 --- a/typegate/tests/utils/test.ts +++ b/typegate/tests/utils/test.ts @@ -28,6 +28,11 @@ export interface ParseOptions { pretty?: boolean; } +export enum SDKLangugage { + Python = "python3", + TypeScript = "deno", +} + interface ServeResult { port: number; cleanup: () => Promise; @@ -179,6 +184,24 @@ export class MetaTest { return engine; } + async serializeTypegraphFromShell( + path: string, + lang: SDKLangugage, + ): Promise { + // run self deployed typegraph + const { stderr, stdout } = await this.shell([lang.toString(), path]); + + if (stderr.length > 0) { + throw new Error(`${stderr}`); + } + + if (stdout.length === 0) { + throw new Error("No typegraph"); + } + + return stdout; + } + async unregister(engine: QueryEngine) { await Promise.all( this.typegate.register diff --git a/typegraph/core/src/conversion/runtimes.rs b/typegraph/core/src/conversion/runtimes.rs index 9b09294c6..97a66a6bc 100644 --- a/typegraph/core/src/conversion/runtimes.rs +++ b/typegraph/core/src/conversion/runtimes.rs @@ -3,9 +3,11 @@ use std::collections::HashMap; +use std::path::PathBuf; use std::rc::Rc; use crate::errors::Result; +use crate::global_store::Store; use crate::runtimes::prisma::get_prisma_context; use crate::runtimes::{ DenoMaterializer, Materializer as RawMaterializer, PythonMaterializer, RandomMaterializer, @@ -229,11 +231,20 @@ impl MaterializerConverter for PythonMaterializer { ("def".to_string(), data) } Module(module) => { - let mut data = IndexMap::new(); - data.insert( - "code".to_string(), - serde_json::Value::String(format!("file:{}", module.file)), - ); + c.add_ref_artifacts(module.artifact_hash.clone(), module.artifact.clone().into())?; + + let deps = module.deps.clone(); + for dep in deps { + Store::register_dep(module.artifact_hash.clone(), dep); + } + + let data = serde_json::from_value(json!({ + "artifact": module.artifact, + "artifact_hash": module.artifact_hash, + "tg_name": None::, + })) + .map_err(|e| e.to_string())?; + ("pymodule".to_string(), data) } Import(import) => { diff --git a/typegraph/core/src/global_store.rs b/typegraph/core/src/global_store.rs index 385b6fab9..bef673b1a 100644 --- a/typegraph/core/src/global_store.rs +++ b/typegraph/core/src/global_store.rs @@ -12,7 +12,9 @@ use crate::wit::utils::Auth as WitAuth; #[allow(unused)] use crate::wit::core::ArtifactResolutionConfig; -use crate::wit::runtimes::{Effect, MaterializerDenoPredefined, MaterializerId}; +use crate::wit::runtimes::{ + Effect, MaterializerDenoPredefined, MaterializerId, ModuleDependencyMeta, +}; use graphql_parser::parse_query; use indexmap::IndexMap; use std::path::PathBuf; @@ -52,6 +54,9 @@ pub struct Store { predefined_deno_functions: HashMap, deno_modules: HashMap, + // module dependencies + artifact_deps: HashMap>, + public_policy_id: PolicyId, prisma_migration_runtime: RuntimeId, @@ -237,6 +242,23 @@ impl Store { with_store_mut(|store| store.random_seed = value) } + pub fn get_deps(artifact_hash: String) -> Vec { + with_store(|store| match store.artifact_deps.get(&artifact_hash) { + Some(deps) => deps.clone(), + None => vec![], + }) + } + + pub fn register_dep(artifact_hash: String, dep: ModuleDependencyMeta) { + with_store_mut(|store| { + store + .artifact_deps + .entry(artifact_hash) + .or_default() + .push(dep) + }) + } + pub fn pick_branch_by_path(supertype_id: TypeId, path: &[String]) -> Result<(Type, TypeId)> { let (_, supertype) = supertype_id.resolve_ref()?; let supertype = &supertype; diff --git a/typegraph/core/src/runtimes/mod.rs b/typegraph/core/src/runtimes/mod.rs index 1c27eeb47..442929c44 100644 --- a/typegraph/core/src/runtimes/mod.rs +++ b/typegraph/core/src/runtimes/mod.rs @@ -340,6 +340,10 @@ impl crate::wit::runtimes::Guest for crate::Lib { Ok(Store::register_materializer(mat)) } + fn get_deps(artifact_hash: String) -> Result, wit::Error> { + Ok(Store::get_deps(artifact_hash)) + } + fn register_random_runtime( data: wit::RandomRuntimeData, ) -> Result { diff --git a/typegraph/core/src/typegraph.rs b/typegraph/core/src/typegraph.rs index a3f061cf9..646c05bfc 100644 --- a/typegraph/core/src/typegraph.rs +++ b/typegraph/core/src/typegraph.rs @@ -24,6 +24,7 @@ use std::collections::hash_map::Entry; use std::collections::HashMap; use std::hash::Hasher as _; +use std::path::PathBuf; use std::rc::Rc; use crate::wit::core::{ @@ -243,6 +244,11 @@ pub fn finalize( Err(e) => return Err(e), }; + let result = match serde_json::to_string_pretty(&tg).map_err(|e| e.to_string().into()) { + Ok(res) => res, + Err(e) => return Err(e), + }; + Ok((result, artifacts)) } diff --git a/typegraph/core/src/utils/postprocess/python_rt.rs b/typegraph/core/src/utils/postprocess/python_rt.rs index 5f2c2242a..0c95bd9bd 100644 --- a/typegraph/core/src/utils/postprocess/python_rt.rs +++ b/typegraph/core/src/utils/postprocess/python_rt.rs @@ -7,24 +7,25 @@ use common::typegraph::{ utils::{map_from_object, object_from_map}, Typegraph, }; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; -use crate::utils::postprocess::{compress_and_encode, PostProcessor}; +use crate::utils::postprocess::PostProcessor; pub struct PythonProcessor; impl PostProcessor for PythonProcessor { fn postprocess(self, tg: &mut Typegraph) -> Result<(), crate::errors::TgError> { + let tg_name = tg.name().unwrap(); for mat in tg.materializers.iter_mut() { if mat.name.as_str() == "pymodule" { let mut mat_data: ModuleMatData = object_from_map(std::mem::take(&mut mat.data)).map_err(|e| e.to_string())?; - let Some(path) = mat_data.code.strip_prefix("file:").to_owned() else { - continue; - }; + let path = &mat_data.artifact; let main_path = fs_host::make_absolute(&PathBuf::from(path))?; - mat_data.code = compress_and_encode(&main_path)?; + let artifact_name = Path::new(path).file_name().unwrap().to_str().unwrap(); + mat_data.artifact = artifact_name.into(); + mat_data.tg_name = Some(tg_name.clone()); mat.data = map_from_object(mat_data).map_err(|e| e.to_string())?; tg.deps.push(main_path); diff --git a/typegraph/core/wit/typegraph.wit b/typegraph/core/wit/typegraph.wit index 24ab9b595..d12ec49d7 100644 --- a/typegraph/core/wit/typegraph.wit +++ b/typegraph/core/wit/typegraph.wit @@ -332,9 +332,17 @@ interface runtimes { fn: string, } + record module-dependency-meta { + path: string, + dep-hash: string, + relative-path-prefix: list, + } + record materializer-python-module { runtime: runtime-id, - file: string, + artifact: string, + artifact-hash: string, + deps: list, } record materializer-python-import { @@ -348,6 +356,7 @@ interface runtimes { from-python-def: func(base: base-materializer, data: materializer-python-def) -> result from-python-module: func(base: base-materializer, data: materializer-python-module) -> result from-python-import: func(base: base-materializer, data: materializer-python-import) -> result + get-deps: func(artifact-hash: string) -> result, error> // random record random-runtime-data { diff --git a/typegraph/node/sdk/src/runtimes/python.ts b/typegraph/node/sdk/src/runtimes/python.ts index 51f840c40..c781408f1 100644 --- a/typegraph/node/sdk/src/runtimes/python.ts +++ b/typegraph/node/sdk/src/runtimes/python.ts @@ -3,9 +3,17 @@ import * as t from "../types.js"; import { runtimes } from "../wit.js"; -import { Effect } from "../gen/interfaces/metatype-typegraph-runtimes.js"; +import { + Effect, + ModuleDependencyMeta, +} from "../gen/interfaces/metatype-typegraph-runtimes.js"; import { Materializer, Runtime } from "./mod.js"; import { fx } from "../index.js"; +import { + getFileHash, + getParentDirectories, + getRelativePath, +} from "../utils/file_utils.js"; interface LambdaMat extends Materializer { fn: string; @@ -21,10 +29,16 @@ interface DefMat extends Materializer { interface PythonImport { name: string; module: string; + deps: Array; secrets?: Array; effect?: Effect; } +// interface DependencyMeta { +// path: string; +// hash: string; +// } + interface ImportMat extends Materializer { module: string; name: string; @@ -84,22 +98,42 @@ export class PythonRuntime extends Runtime { } as DefMat); } - import< + async import< I extends t.Typedef = t.Typedef, O extends t.Typedef = t.Typedef, >( inp: I, out: O, - { name, module, effect = fx.read(), secrets = [] }: PythonImport, - ): t.Func { + { name, module, deps = [], effect = fx.read(), secrets = [] }: PythonImport, + ): Promise> { const base = { runtime: this._id, effect, }; + const artifactHash = await getFileHash(module); + + // generate dep meta + const depMetas: ModuleDependencyMeta[] = []; + for (const dep of deps) { + const depHash = await getFileHash(dep); + const depParentDirs = getParentDirectories(dep); + const depMeta: ModuleDependencyMeta = { + path: dep, + depHash: depHash, + relativePathPrefix: getRelativePath( + getParentDirectories(module), + depParentDirs, + ), + }; + depMetas.push(depMeta); + } + const matId = runtimes.fromPythonModule(base, { - file: module, + artifact: module, runtime: this._id, + artifactHash: artifactHash, + deps: depMetas, }); const pyModMatId = runtimes.fromPythonImport(base, { diff --git a/typegraph/node/sdk/src/tg_artifact_upload.ts b/typegraph/node/sdk/src/tg_artifact_upload.ts new file mode 100644 index 000000000..4ef871882 --- /dev/null +++ b/typegraph/node/sdk/src/tg_artifact_upload.ts @@ -0,0 +1,151 @@ +// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +// SPDX-License-Identifier: MPL-2.0 + +import { BasicAuth } from "./tg_deploy.js"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import { runtimes } from "./wit.js"; +import { ModuleDependencyMeta } from "./gen/interfaces/metatype-typegraph-runtimes.js"; + +export interface UploadArtifactMeta { + name: string; + artifact_hash: string; + artifact_size_in_bytes: number; + path_suffix: string[]; +} + +export class ArtifactUploader { + private getUploadUrl: URL; + + constructor( + private baseUrl: string, + private refArtifacts: [string, string][], + private tgName: string, + private auth: BasicAuth | undefined, + private headers: Headers, + ) { + const suffix = `${tgName}/get-upload-url`; + this.getUploadUrl = new URL(suffix, baseUrl); + } + + private async fetchUploadUrl( + artifactPath: string, + artifactHash: string, + artifactContent: Uint8Array, + pathSuffix: string[], + ): Promise { + const artifactMeta: UploadArtifactMeta = { + name: path.basename(artifactPath), + artifact_hash: artifactHash, + artifact_size_in_bytes: artifactContent.length, + path_suffix: pathSuffix, + }; + + const artifactJson = JSON.stringify(artifactMeta); + const uploadUrlResponse = await fetch(this.getUploadUrl, { + method: "PUT", + headers: this.headers, + body: artifactJson, + }); + + // console.log("******************A", uploadUrlResponse); + const decodedResponse = await uploadUrlResponse.json(); + + return decodedResponse.uploadUrl as string; + } + + private async upload( + url: string, + content: Uint8Array, + artifactPath: string, + ): Promise { + const uploadHeaders = new Headers({ + "Content-Type": "application/octet-stream", + }); + + if (this.auth) { + uploadHeaders.append("Authorization", this.auth.asHeaderValue()); + } + + const artifactUploadResponse = await fetch(url, { + method: "PUT", + headers: uploadHeaders, + body: content, + }); + + const _ = await artifactUploadResponse.json(); + if (!artifactUploadResponse.ok) { + throw new Error( + `Failed to upload artifact ${artifactPath} to typegate: ${artifactUploadResponse.status} ${artifactUploadResponse.statusText}`, + ); + } + } + + async uploadArtifacts(): Promise { + for (let [artifactHash, artifactPath] of this.refArtifacts) { + await this.uploadArtifact(artifactHash, artifactPath); + } + } + + private async uploadArtifact( + artifactHash: string, + artifactPath: string, + ): Promise { + try { + await fs.promises.access(artifactPath); + } catch (err) { + throw new Error(`Failed to access artifact ${artifactPath}: ${err}`); + } + let artifactContent: Buffer; + try { + artifactContent = await fs.promises.readFile(artifactPath); + } catch (err) { + throw new Error(`Failed to read artifact ${artifactPath}: ${err}`); + } + const byteArray = new Uint8Array(artifactContent); + + const artifactUploadUrl = await this.fetchUploadUrl( + artifactPath, + artifactHash, + byteArray, + [artifactHash], + ); + + await this.upload(artifactUploadUrl, byteArray, artifactPath); + + await this.uploadArtifactDependencies(artifactHash); + } + + private async uploadArtifactDependencies( + artifactHash: string, + ): Promise { + const depMetas = runtimes.getDeps(artifactHash); + + for (let dep of depMetas) { + const { depHash, path: depPath, relativePathPrefix }: + ModuleDependencyMeta = dep; + + try { + await fs.promises.access(depPath); + } catch (err) { + throw new Error(`Failed to access artifact ${path}: ${err}`); + } + let depContent: Buffer; + try { + depContent = await fs.promises.readFile(depPath); + } catch (err) { + throw new Error(`Failed to read artifact ${path}: ${err}`); + } + const byteArray = new Uint8Array(depContent); + + const depUploadUrl = await this.fetchUploadUrl( + depPath, + depHash, + byteArray, + [artifactHash, ...relativePathPrefix], + ); + + await this.upload(depUploadUrl, byteArray, depPath); + } + } +} diff --git a/typegraph/node/sdk/src/tg_deploy.ts b/typegraph/node/sdk/src/tg_deploy.ts index e1389d2ad..681a08fde 100644 --- a/typegraph/node/sdk/src/tg_deploy.ts +++ b/typegraph/node/sdk/src/tg_deploy.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 import { ArtifactResolutionConfig } from "./gen/interfaces/metatype-typegraph-core.js"; +import { ArtifactUploader } from "./tg_artifact_upload.js"; import { TypegraphOutput } from "./typegraph.js"; import { wit_utils } from "./wit.js"; import * as fsp from "node:fs/promises"; diff --git a/typegraph/node/sdk/src/utils/file_utils.ts b/typegraph/node/sdk/src/utils/file_utils.ts index 45e2b00ec..13d44f19e 100644 --- a/typegraph/node/sdk/src/utils/file_utils.ts +++ b/typegraph/node/sdk/src/utils/file_utils.ts @@ -4,11 +4,11 @@ import * as fs from "node:fs"; import * as crypto from "node:crypto"; import { wit_utils } from "../wit.js"; -import { Artifact } from "../gen/interfaces/metatype-typegraph-core.js"; +import * as path from "node:path"; -export async function getArtifactMeta(path: string): Promise { +export async function getFileHash(filePath: string): Promise { const cwd = wit_utils.getCwd(); - const filePath = `${cwd}/${path}`; + filePath = `${cwd}/${filePath}`; const hash = crypto.createHash("sha256"); let file; @@ -31,11 +31,7 @@ export async function getArtifactMeta(path: string): Promise { hash.update(buffer.subarray(0, numBytesRead)); } while (numBytesRead > 0); - return { - path, - hash: hash.digest("hex"), - size: bytesRead, - }; + return hash.digest("hex"); } catch (err) { throw new Error(`Failed to calculate hash for ${filePath}: \n${err}`); } finally { @@ -44,3 +40,31 @@ export async function getArtifactMeta(path: string): Promise { } } } + +export function getParentDirectories(filePath: string) { + const directories = []; + let currentDir = path.dirname(filePath); + while (currentDir !== path.dirname(currentDir)) { + directories.push(path.basename(currentDir)); + currentDir = path.dirname(currentDir); + } + return directories.reverse(); +} + +export function getRelativePath( + moduleParentDirs: string[], + depParentDirs: string[], +): string[] { + let common = 0; + let maxLength = Math.min(moduleParentDirs.length, depParentDirs.length); + + for (let i = 0; i < maxLength; i++) { + if (moduleParentDirs[i] === depParentDirs[i]) { + common += 1; + } else { + break; + } + } + + return depParentDirs.slice(common); +} diff --git a/typegraph/python/typegraph/graph/shared_types.py b/typegraph/python/typegraph/graph/shared_types.py index 359984aef..ea014b673 100644 --- a/typegraph/python/typegraph/graph/shared_types.py +++ b/typegraph/python/typegraph/graph/shared_types.py @@ -4,6 +4,7 @@ from base64 import b64encode from dataclasses import dataclass from typing import Callable, List, Optional, Tuple + from typegraph.wit import ArtifactResolutionConfig @@ -29,3 +30,4 @@ def as_header_value(self): "utf-8" ) return f"Basic {payload}" + return f"Basic {payload}" diff --git a/typegraph/python/typegraph/graph/tg_artifact_upload.py b/typegraph/python/typegraph/graph/tg_artifact_upload.py new file mode 100644 index 000000000..99e811e97 --- /dev/null +++ b/typegraph/python/typegraph/graph/tg_artifact_upload.py @@ -0,0 +1,149 @@ +# Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0. +# SPDX-License-Identifier: MPL-2.0 + +import json +import os +from dataclasses import dataclass +from typing import Dict, List, Tuple +from urllib import request + +from typegraph.gen.types import Err, Result +from typegraph.graph.shared_types import BasicAuth +from typegraph.graph.tg_deploy import handle_response +from typegraph.wit import runtimes, store + + +@dataclass +class UploadArtifactMeta: + name: str + artifact_hash: str + artifact_size_in_bytes: int + path_suffix: List[str] + + +class ArtifactUploader: + base_url: str + ref_artifacts: List[Tuple[str, str]] + get_upload_url: str + tg_name: str + auth: BasicAuth + headers: Dict[str, str] + + def __init__( + self, + base_url: str, + artifacts: List[Tuple[str, str]], + tg_name: str, + auth: BasicAuth, + headers: Dict[str, str], + ) -> None: + self.base_url = base_url + self.ref_artifacts = artifacts + self.tg_name = tg_name + sep = "/" if not base_url.endswith("/") else "" + self.get_upload_url = base_url + sep + tg_name + "/get-upload-url" + self.auth = auth + self.headers = headers + + # TODO: fetch all the upload urls in one request + def __fetch_upload_url( + self, + artifact_path: str, + artifact_hash: str, + artifact_content: bytes, + path_suffix: List[str], + ) -> str: + artifact = UploadArtifactMeta( + name=os.path.basename(artifact_path), + artifact_hash=artifact_hash, + artifact_size_in_bytes=len(artifact_content), + path_suffix=path_suffix, + ) + + artifact_json = json.dumps(artifact.__dict__).encode() + req = request.Request( + url=self.get_upload_url, + method="PUT", + headers=self.headers, + data=artifact_json, + ) + + response = handle_response(request.urlopen(req).read().decode()) + return response["uploadUrl"] + + def __upload( + self, + url: str, + content: bytes, + artifact_path: str, + ) -> Result[str, Err]: + upload_headers = {"Content-Type": "application/octet-stream"} + if self.auth is not None: + upload_headers["Authorization"] = self.auth.as_header_value() + upload_req = request.Request( + url=url, + method="PUT", + data=content, + headers=upload_headers, + ) + response = request.urlopen(upload_req) + if response.status != 200: + raise Exception( + f"Failed to upload artifact {artifact_path} to typegate: {response.read()}" + ) + + return response + + def upload_artifacts( + self, + ) -> Result[None, Err]: + for artifact_hash, artifact_path in self.ref_artifacts: + self.__upload_artifact(artifact_hash, artifact_path) + + def __upload_artifact(self, artifact_hash: str, artifact_path: str): + with open(artifact_path, "rb") as artifact: + artifact_content = artifact.read() + artifact_upload_url = self.__fetch_upload_url( + artifact_path, artifact_hash, artifact_content, [artifact_hash] + ) + + _upload_result = self.__upload( + artifact_upload_url, artifact_content, artifact_path + ) + + self.__upload_artifact_dependencies(artifact_hash) + + def __upload_artifact_dependencies(self, artifact_hash: str) -> Result[None, Err]: + dep_metas = runtimes.get_deps(store, artifact_hash) + if isinstance(dep_metas, Err): + raise Exception(dep_metas.value) + + dep_metas = dep_metas.value + + for dep_meta in dep_metas: + dep_hash = dep_meta.dep_hash + dep_path = dep_meta.path + relative_prefix = dep_meta.relative_path_prefix + + with open(dep_path, "rb") as dep: + dep_content = dep.read() + dep_upload_url = self.__fetch_upload_url( + dep_path, dep_hash, dep_content, [artifact_hash, *relative_prefix] + ) + + _upload_result = self.__upload(dep_upload_url, dep_content, dep_path) + + +""" + + what would uploading artifact with deps look like: + - get an upload url for the artifact, and use the artifact_hash as a suffix to store the artifact and the deps. The suffix is to be appended to the path where the artifact and the deps are gonna be stored + - get all the deps of the artifact + - upload them in parallel + + + - serialize(done, not tested) => upload(done, not tested) => resolve(done, not tested) + + - testing left + +""" diff --git a/typegraph/python/typegraph/graph/tg_deploy.py b/typegraph/python/typegraph/graph/tg_deploy.py index 38ceaf3be..a6ef4b34a 100644 --- a/typegraph/python/typegraph/graph/tg_deploy.py +++ b/typegraph/python/typegraph/graph/tg_deploy.py @@ -2,7 +2,6 @@ # SPDX-License-Identifier: MPL-2.0 import json -import os from dataclasses import dataclass from typing import Dict, Optional, Union from urllib import request @@ -10,6 +9,7 @@ from typegraph.gen.exports.utils import QueryDeployParams from typegraph.gen.types import Err from typegraph.graph.shared_types import BasicAuth +from typegraph.graph.tg_artifact_upload import ArtifactUploader from typegraph.graph.typegraph import TypegraphOutput from typegraph.wit import ArtifactResolutionConfig, store, wit_utils @@ -58,39 +58,14 @@ def tg_deploy(tg: TypegraphOutput, params: TypegraphDeployParams) -> DeployResul ref_artifacts = serialized.ref_artifacts # upload the referred artifacts - # TODO: fetch all the upload urls in one request - get_upload_url = params.base_url + sep + tg.name + "/get-upload-url" - for artifact_hash, artifact_path in ref_artifacts: - with open(artifact_path, "rb") as artifact: - artifact_content = artifact.read() - artifact = UploadArtifactMeta( - name=os.path.basename(artifact_path), - artifact_hash=artifact_hash, - artifact_size_in_bytes=len(artifact_content), - ) - - artifact_json = json.dumps(artifact.__dict__).encode() - req = request.Request( - url=get_upload_url, method="PUT", headers=headers, data=artifact_json - ) - - response = handle_response(request.urlopen(req).read().decode()) - artifact_upload_url = response["uploadUrl"] - - upload_headers = {"Content-Type": "application/octet-stream"} - if params.auth is not None: - upload_headers["Authorization"] = params.auth.as_header_value() - upload_req = request.Request( - url=artifact_upload_url, - method="PUT", - data=artifact_content, - headers=upload_headers, - ) - response = request.urlopen(upload_req) - if response.status != 200: - raise Exception( - f"Failed to upload artifact {artifact_path} to typegate: {response.read()}" - ) + artifact_uploader = ArtifactUploader( + params.base_url, + ref_artifacts, + tg.name, + params.auth, + headers, + ) + artifact_uploader.upload_artifacts() # deploy the typegraph res = wit_utils.gql_deploy_query( diff --git a/typegraph/python/typegraph/runtimes/python.py b/typegraph/python/typegraph/runtimes/python.py index 81b459849..011e8005d 100644 --- a/typegraph/python/typegraph/runtimes/python.py +++ b/typegraph/python/typegraph/runtimes/python.py @@ -6,7 +6,6 @@ from typing import TYPE_CHECKING, List, Optional from astunparse import unparse - from typegraph.gen.exports.runtimes import ( BaseMaterializer, Effect, @@ -15,9 +14,11 @@ MaterializerPythonImport, MaterializerPythonLambda, MaterializerPythonModule, + ModuleDependencyMeta, ) from typegraph.gen.types import Err from typegraph.runtimes.base import Materializer, Runtime +from typegraph.utils import get_file_hash, get_parent_directories, get_relative_path from typegraph.wit import runtimes, store if TYPE_CHECKING: @@ -93,15 +94,39 @@ def import_( *, module: str, name: str, + deps: List[str] = [], effect: Optional[Effect] = None, secrets: Optional[List[str]] = None, ): effect = effect or EffectRead() secrets = secrets or [] + artifact_hash = get_file_hash(module) + + # generate dep_metas + dep_metas = [] + for dep in deps: + dep_hash = get_file_hash(dep) + dep_parent_dirs = get_parent_directories(dep) + dep_meta = ModuleDependencyMeta( + path=dep, + dep_hash=dep_hash, + relative_path_prefix=get_relative_path( + get_parent_directories(module), dep_parent_dirs + ), + ) + dep_metas.append(dep_meta) + base = BaseMaterializer(runtime=self.id.value, effect=effect) mat_id = runtimes.from_python_module( - store, base, MaterializerPythonModule(file=module, runtime=self.id.value) + store, + base, + MaterializerPythonModule( + artifact=module, + artifact_hash=artifact_hash, + deps=dep_metas, + runtime=self.id.value, + ), ) if isinstance(mat_id, Err): @@ -172,3 +197,4 @@ def visit_Lambda(self, node): def visit_FunctionDef(self, node): self.defs.append((node.name, unparse(node).strip())) + self.defs.append((node.name, unparse(node).strip())) diff --git a/typegraph/python/typegraph/utils.py b/typegraph/python/typegraph/utils.py index bbd8d3154..e0f9f43bf 100644 --- a/typegraph/python/typegraph/utils.py +++ b/typegraph/python/typegraph/utils.py @@ -95,3 +95,35 @@ def get_file_hash(file_path: str) -> str: sha256_hasher.update(chunk) return sha256_hasher.hexdigest() + + +def get_parent_directories( + path: str, +) -> List[str]: + parents = [] + + while True: + path, folder = os.path.split(path) + if folder: + parents.append(folder) + else: + if path: + parents.append(path) + break + + return parents[::-1] + + +def get_relative_path( + module_path: List[str], + dep_path: List[str], +) -> List[str]: + common = 0 + + max_len = min(len(module_path), len(dep_path)) + for i in range(max_len): + if module_path[i] != dep_path[i]: + break + common += 1 + + return dep_path[common:] diff --git a/website/static/specs/0.0.3.json b/website/static/specs/0.0.3.json index 2fc86e0f9..2cba2cc1f 100644 --- a/website/static/specs/0.0.3.json +++ b/website/static/specs/0.0.3.json @@ -2,14 +2,7 @@ "$schema": "http://json-schema.org/draft-07/schema#", "title": "Typegraph", "type": "object", - "required": [ - "$id", - "materializers", - "meta", - "policies", - "runtimes", - "types" - ], + "required": ["$id", "materializers", "meta", "policies", "runtimes", "types"], "properties": { "$id": { "type": "string" @@ -47,20 +40,11 @@ "oneOf": [ { "type": "object", - "required": [ - "as_id", - "item", - "policies", - "runtime", - "title", - "type" - ], + "required": ["as_id", "item", "policies", "runtime", "title", "type"], "properties": { "type": { "type": "string", - "enum": [ - "optional" - ] + "enum": ["optional"] }, "title": { "type": "string" @@ -78,10 +62,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -96,10 +77,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -122,19 +100,11 @@ }, { "type": "object", - "required": [ - "as_id", - "policies", - "runtime", - "title", - "type" - ], + "required": ["as_id", "policies", "runtime", "title", "type"], "properties": { "type": { "type": "string", - "enum": [ - "boolean" - ] + "enum": ["boolean"] }, "title": { "type": "string" @@ -152,10 +122,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -170,10 +137,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -190,19 +154,11 @@ }, { "type": "object", - "required": [ - "as_id", - "policies", - "runtime", - "title", - "type" - ], + "required": ["as_id", "policies", "runtime", "title", "type"], "properties": { "type": { "type": "string", - "enum": [ - "float" - ] + "enum": ["float"] }, "title": { "type": "string" @@ -220,10 +176,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -238,10 +191,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -255,57 +205,34 @@ "type": "boolean" }, "minimum": { - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "format": "double" }, "maximum": { - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "format": "double" }, "exclusiveMinimum": { - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "format": "double" }, "exclusiveMaximum": { - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "format": "double" }, "multipleOf": { - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "format": "double" } } }, { "type": "object", - "required": [ - "as_id", - "policies", - "runtime", - "title", - "type" - ], + "required": ["as_id", "policies", "runtime", "title", "type"], "properties": { "type": { "type": "string", - "enum": [ - "integer" - ] + "enum": ["integer"] }, "title": { "type": "string" @@ -323,10 +250,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -341,10 +265,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -358,57 +279,34 @@ "type": "boolean" }, "minimum": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" }, "maximum": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" }, "exclusiveMinimum": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" }, "exclusiveMaximum": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" }, "multipleOf": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" } } }, { "type": "object", - "required": [ - "as_id", - "policies", - "runtime", - "title", - "type" - ], + "required": ["as_id", "policies", "runtime", "title", "type"], "properties": { "type": { "type": "string", - "enum": [ - "string" - ] + "enum": ["string"] }, "title": { "type": "string" @@ -426,10 +324,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -444,10 +339,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -461,26 +353,17 @@ "type": "boolean" }, "minLength": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, "maxLength": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, "pattern": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "format": { "anyOf": [ @@ -496,19 +379,11 @@ }, { "type": "object", - "required": [ - "as_id", - "policies", - "runtime", - "title", - "type" - ], + "required": ["as_id", "policies", "runtime", "title", "type"], "properties": { "type": { "type": "string", - "enum": [ - "file" - ] + "enum": ["file"] }, "title": { "type": "string" @@ -526,10 +401,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -544,10 +416,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -561,26 +430,17 @@ "type": "boolean" }, "minSize": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, "maxSize": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, "mimeTypes": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -600,9 +460,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "object" - ] + "enum": ["object"] }, "title": { "type": "string" @@ -620,10 +478,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -638,10 +493,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -684,9 +536,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "list" - ] + "enum": ["list"] }, "title": { "type": "string" @@ -704,10 +554,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -722,10 +569,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -744,26 +588,17 @@ "minimum": 0.0 }, "maxItems": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, "minItems": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, "uniqueItems": { - "type": [ - "boolean", - "null" - ] + "type": ["boolean", "null"] } } }, @@ -783,9 +618,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "function" - ] + "enum": ["function"] }, "title": { "type": "string" @@ -803,10 +636,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -821,10 +651,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -863,10 +690,7 @@ "minimum": 0.0 }, "rate_weight": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, @@ -888,9 +712,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "union" - ] + "enum": ["union"] }, "title": { "type": "string" @@ -908,10 +730,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -926,10 +745,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -966,9 +782,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "either" - ] + "enum": ["either"] }, "title": { "type": "string" @@ -986,10 +800,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -1004,10 +815,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -1033,19 +841,11 @@ }, { "type": "object", - "required": [ - "as_id", - "policies", - "runtime", - "title", - "type" - ], + "required": ["as_id", "policies", "runtime", "title", "type"], "properties": { "type": { "type": "string", - "enum": [ - "any" - ] + "enum": ["any"] }, "title": { "type": "string" @@ -1063,10 +863,7 @@ }, "description": { "default": null, - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "injection": { "default": null, @@ -1081,10 +878,7 @@ }, "enum": { "default": null, - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -1117,34 +911,22 @@ "type": "object", "properties": { "read": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, "create": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, "delete": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, "update": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 } @@ -1154,16 +936,11 @@ "oneOf": [ { "type": "object", - "required": [ - "data", - "source" - ], + "required": ["data", "source"], "properties": { "source": { "type": "string", - "enum": [ - "static" - ] + "enum": ["static"] }, "data": { "$ref": "#/definitions/InjectionData_for_String" @@ -1172,16 +949,11 @@ }, { "type": "object", - "required": [ - "data", - "source" - ], + "required": ["data", "source"], "properties": { "source": { "type": "string", - "enum": [ - "context" - ] + "enum": ["context"] }, "data": { "$ref": "#/definitions/InjectionData_for_String" @@ -1190,16 +962,11 @@ }, { "type": "object", - "required": [ - "data", - "source" - ], + "required": ["data", "source"], "properties": { "source": { "type": "string", - "enum": [ - "secret" - ] + "enum": ["secret"] }, "data": { "$ref": "#/definitions/InjectionData_for_String" @@ -1208,16 +975,11 @@ }, { "type": "object", - "required": [ - "data", - "source" - ], + "required": ["data", "source"], "properties": { "source": { "type": "string", - "enum": [ - "parent" - ] + "enum": ["parent"] }, "data": { "$ref": "#/definitions/InjectionData_for_uint32" @@ -1226,16 +988,11 @@ }, { "type": "object", - "required": [ - "data", - "source" - ], + "required": ["data", "source"], "properties": { "source": { "type": "string", - "enum": [ - "dynamic" - ] + "enum": ["dynamic"] }, "data": { "$ref": "#/definitions/InjectionData_for_String" @@ -1244,16 +1001,11 @@ }, { "type": "object", - "required": [ - "data", - "source" - ], + "required": ["data", "source"], "properties": { "source": { "type": "string", - "enum": [ - "random" - ] + "enum": ["random"] }, "data": { "$ref": "#/definitions/InjectionData_for_String" @@ -1277,9 +1029,7 @@ }, "SingleValue_for_String": { "type": "object", - "required": [ - "value" - ], + "required": ["value"], "properties": { "value": { "type": "string" @@ -1303,9 +1053,7 @@ }, "SingleValue_for_uint32": { "type": "object", - "required": [ - "value" - ], + "required": ["value"], "properties": { "value": { "type": "integer", @@ -1330,10 +1078,7 @@ }, "FunctionParameterTransform": { "type": "object", - "required": [ - "resolver_input", - "transform_root" - ], + "required": ["resolver_input", "transform_root"], "properties": { "resolver_input": { "type": "integer", @@ -1347,10 +1092,7 @@ }, "ParameterTransformNode": { "type": "object", - "required": [ - "data", - "typeIdx" - ], + "required": ["data", "typeIdx"], "properties": { "typeIdx": { "type": "integer", @@ -1376,16 +1118,11 @@ "oneOf": [ { "type": "object", - "required": [ - "name", - "source" - ], + "required": ["name", "source"], "properties": { "source": { "type": "string", - "enum": [ - "arg" - ] + "enum": ["arg"] }, "name": { "type": "string" @@ -1394,16 +1131,11 @@ }, { "type": "object", - "required": [ - "source", - "valueJson" - ], + "required": ["source", "valueJson"], "properties": { "source": { "type": "string", - "enum": [ - "static" - ] + "enum": ["static"] }, "valueJson": { "type": "string" @@ -1412,16 +1144,11 @@ }, { "type": "object", - "required": [ - "key", - "source" - ], + "required": ["key", "source"], "properties": { "source": { "type": "string", - "enum": [ - "secret" - ] + "enum": ["secret"] }, "key": { "type": "string" @@ -1430,16 +1157,11 @@ }, { "type": "object", - "required": [ - "key", - "source" - ], + "required": ["key", "source"], "properties": { "source": { "type": "string", - "enum": [ - "context" - ] + "enum": ["context"] }, "key": { "type": "string" @@ -1448,16 +1170,11 @@ }, { "type": "object", - "required": [ - "parentIdx", - "source" - ], + "required": ["parentIdx", "source"], "properties": { "source": { "type": "string", - "enum": [ - "parent" - ] + "enum": ["parent"] }, "parentIdx": { "type": "integer", @@ -1472,16 +1189,11 @@ "oneOf": [ { "type": "object", - "required": [ - "fields", - "type" - ], + "required": ["fields", "type"], "properties": { "type": { "type": "string", - "enum": [ - "object" - ] + "enum": ["object"] }, "fields": { "type": "object", @@ -1493,16 +1205,11 @@ }, { "type": "object", - "required": [ - "items", - "type" - ], + "required": ["items", "type"], "properties": { "type": { "type": "string", - "enum": [ - "array" - ] + "enum": ["array"] }, "items": { "type": "array", @@ -1516,12 +1223,7 @@ }, "Materializer": { "type": "object", - "required": [ - "data", - "effect", - "name", - "runtime" - ], + "required": ["data", "effect", "name", "runtime"], "properties": { "name": { "type": "string" @@ -1542,9 +1244,7 @@ }, "Effect": { "type": "object", - "required": [ - "idempotent" - ], + "required": ["idempotent"], "properties": { "effect": { "anyOf": [ @@ -1563,12 +1263,7 @@ }, "EffectType": { "type": "string", - "enum": [ - "create", - "update", - "delete", - "read" - ] + "enum": ["create", "update", "delete", "read"] }, "TGRuntime": { "anyOf": [ @@ -1584,16 +1279,11 @@ "oneOf": [ { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "deno" - ] + "enum": ["deno"] }, "data": { "$ref": "#/definitions/DenoRuntimeData" @@ -1602,16 +1292,11 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "graphql" - ] + "enum": ["graphql"] }, "data": { "$ref": "#/definitions/GraphQLRuntimeData" @@ -1620,16 +1305,11 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "http" - ] + "enum": ["http"] }, "data": { "$ref": "#/definitions/HTTPRuntimeData" @@ -1638,16 +1318,11 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "python_wasi" - ] + "enum": ["python_wasi"] }, "data": { "$ref": "#/definitions/PythonRuntimeData" @@ -1656,16 +1331,11 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "random" - ] + "enum": ["random"] }, "data": { "$ref": "#/definitions/RandomRuntimeData" @@ -1674,16 +1344,11 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "prisma" - ] + "enum": ["prisma"] }, "data": { "$ref": "#/definitions/PrismaRuntimeData" @@ -1692,16 +1357,11 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "prisma_migration" - ] + "enum": ["prisma_migration"] }, "data": { "$ref": "#/definitions/PrismaMigrationRuntimeData" @@ -1710,16 +1370,11 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "s3" - ] + "enum": ["s3"] }, "data": { "$ref": "#/definitions/S3RuntimeData" @@ -1728,16 +1383,11 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "temporal" - ] + "enum": ["temporal"] }, "data": { "$ref": "#/definitions/TemporalRuntimeData" @@ -1746,16 +1396,11 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "wasmedge" - ] + "enum": ["wasmedge"] }, "data": { "$ref": "#/definitions/WasmEdgeRuntimeData" @@ -1764,16 +1409,11 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "typegate" - ] + "enum": ["typegate"] }, "data": { "$ref": "#/definitions/TypegateRuntimeData" @@ -1782,16 +1422,11 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "typegraph" - ] + "enum": ["typegraph"] }, "data": { "$ref": "#/definitions/TypegraphRuntimeData" @@ -1802,10 +1437,7 @@ }, "DenoRuntimeData": { "type": "object", - "required": [ - "permissions", - "worker" - ], + "required": ["permissions", "worker"], "properties": { "worker": { "type": "string" @@ -1818,9 +1450,7 @@ }, "GraphQLRuntimeData": { "type": "object", - "required": [ - "endpoint" - ], + "required": ["endpoint"], "properties": { "endpoint": { "type": "string" @@ -1829,24 +1459,16 @@ }, "HTTPRuntimeData": { "type": "object", - "required": [ - "endpoint" - ], + "required": ["endpoint"], "properties": { "endpoint": { "type": "string" }, "cert_secret": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "basic_auth_secret": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } } }, @@ -1854,10 +1476,7 @@ "type": "object", "properties": { "config": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } } }, @@ -1865,18 +1484,12 @@ "type": "object", "properties": { "seed": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, "reset": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } } }, @@ -1978,9 +1591,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "scalar" - ] + "enum": ["scalar"] }, "key": { "type": "string" @@ -2030,9 +1641,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "relationship" - ] + "enum": ["relationship"] }, "key": { "type": "string" @@ -2065,58 +1674,41 @@ "oneOf": [ { "type": "object", - "required": [ - "type" - ], + "required": ["type"], "properties": { "type": { "type": "string", - "enum": [ - "Boolean" - ] + "enum": ["Boolean"] } } }, { "type": "object", - "required": [ - "type" - ], + "required": ["type"], "properties": { "type": { "type": "string", - "enum": [ - "Int" - ] + "enum": ["Int"] } } }, { "type": "object", - "required": [ - "type" - ], + "required": ["type"], "properties": { "type": { "type": "string", - "enum": [ - "Float" - ] + "enum": ["Float"] } } }, { "type": "object", - "required": [ - "format", - "type" - ], + "required": ["format", "type"], "properties": { "type": { "type": "string", - "enum": [ - "String" - ] + "enum": ["String"] }, "format": { "$ref": "#/definitions/StringType" @@ -2127,19 +1719,11 @@ }, "StringType": { "type": "string", - "enum": [ - "Plain", - "Uuid", - "DateTime" - ] + "enum": ["Plain", "Uuid", "DateTime"] }, "Cardinality": { "type": "string", - "enum": [ - "optional", - "one", - "many" - ] + "enum": ["optional", "one", "many"] }, "ManagedInjection": { "type": "object", @@ -2168,24 +1752,15 @@ }, "Injection2": { "type": "string", - "enum": [ - "DateNow" - ] + "enum": ["DateNow"] }, "Side": { "type": "string", - "enum": [ - "left", - "right" - ] + "enum": ["left", "right"] }, "Relationship": { "type": "object", - "required": [ - "left", - "name", - "right" - ], + "required": ["left", "name", "right"], "properties": { "name": { "type": "string" @@ -2200,11 +1775,7 @@ }, "RelationshipModel": { "type": "object", - "required": [ - "cardinality", - "field", - "type_idx" - ], + "required": ["cardinality", "field", "type_idx"], "properties": { "type_idx": { "type": "integer", @@ -2221,16 +1792,10 @@ }, "MigrationOptions": { "type": "object", - "required": [ - "create", - "reset" - ], + "required": ["create", "reset"], "properties": { "migration_files": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "create": { "type": "boolean" @@ -2272,10 +1837,7 @@ }, "TemporalRuntimeData": { "type": "object", - "required": [ - "host", - "name" - ], + "required": ["host", "name"], "properties": { "name": { "type": "string" @@ -2289,10 +1851,7 @@ "type": "object", "properties": { "config": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } } }, @@ -2304,10 +1863,7 @@ }, "UnknownRuntime": { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string" @@ -2320,10 +1876,7 @@ }, "Policy": { "type": "object", - "required": [ - "materializer", - "name" - ], + "required": ["materializer", "name"], "properties": { "name": { "type": "string" @@ -2347,10 +1900,7 @@ ], "properties": { "prefix": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "secrets": { "type": "array", @@ -2383,11 +1933,8 @@ "version": { "type": "string" }, - "randomSeed": { - "type": [ - "integer", - "null" - ], + "random_seed": { + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 }, @@ -2401,10 +1948,7 @@ }, "Queries": { "type": "object", - "required": [ - "dynamic", - "endpoints" - ], + "required": ["dynamic", "endpoints"], "properties": { "dynamic": { "type": "boolean" @@ -2455,10 +1999,7 @@ "type": "boolean" }, "max_age_sec": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint32", "minimum": 0.0 } @@ -2466,11 +2007,7 @@ }, "Auth": { "type": "object", - "required": [ - "auth_data", - "name", - "protocol" - ], + "required": ["auth_data", "name", "protocol"], "properties": { "name": { "type": "string" @@ -2486,20 +2023,11 @@ }, "AuthProtocol": { "type": "string", - "enum": [ - "oauth2", - "jwt", - "basic" - ] + "enum": ["oauth2", "jwt", "basic"] }, "Rate": { "type": "object", - "required": [ - "local_excess", - "query_limit", - "window_limit", - "window_sec" - ], + "required": ["local_excess", "query_limit", "window_limit", "window_sec"], "properties": { "window_limit": { "type": "integer", @@ -2517,10 +2045,7 @@ "minimum": 0.0 }, "context_identifier": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "local_excess": { "type": "integer", @@ -2531,11 +2056,7 @@ }, "Artifact": { "type": "object", - "required": [ - "hash", - "path", - "size" - ], + "required": ["hash", "path", "size"], "properties": { "path": { "type": "string" @@ -2553,9 +2074,7 @@ "FunctionMatData": { "title": "FunctionMatData", "type": "object", - "required": [ - "script" - ], + "required": ["script"], "properties": { "script": { "type": "string" @@ -2565,9 +2084,7 @@ "ModuleMatData": { "title": "ModuleMatData", "type": "object", - "required": [ - "code" - ], + "required": ["code"], "properties": { "code": { "type": "string" @@ -2579,31 +2096,21 @@ "oneOf": [ { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "presign_get" - ] + "enum": ["presign_get"] }, "data": { "type": "object", - "required": [ - "bucket" - ], + "required": ["bucket"], "properties": { "bucket": { "type": "string" }, "expiry_secs": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint", "minimum": 0.0 } @@ -2613,37 +2120,24 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "presign_put" - ] + "enum": ["presign_put"] }, "data": { "type": "object", - "required": [ - "bucket" - ], + "required": ["bucket"], "properties": { "bucket": { "type": "string" }, "content_type": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "expiry_secs": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint", "minimum": 0.0 } @@ -2653,22 +2147,15 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "list" - ] + "enum": ["list"] }, "data": { "type": "object", - "required": [ - "bucket" - ], + "required": ["bucket"], "properties": { "bucket": { "type": "string" @@ -2679,22 +2166,15 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "upload" - ] + "enum": ["upload"] }, "data": { "type": "object", - "required": [ - "bucket" - ], + "required": ["bucket"], "properties": { "bucket": { "type": "string" @@ -2705,22 +2185,15 @@ }, { "type": "object", - "required": [ - "data", - "name" - ], + "required": ["data", "name"], "properties": { "name": { "type": "string", - "enum": [ - "upload_all" - ] + "enum": ["upload_all"] }, "data": { "type": "object", - "required": [ - "bucket" - ], + "required": ["bucket"], "properties": { "bucket": { "type": "string" @@ -2734,10 +2207,7 @@ "PrismaOperationMatData": { "title": "PrismaOperationMatData", "type": "object", - "required": [ - "operation", - "table" - ], + "required": ["operation", "table"], "properties": { "table": { "type": "string" @@ -2746,10 +2216,7 @@ "type": "string" }, "ordered_keys": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -2759,10 +2226,7 @@ "WasiMatData": { "title": "WasiMatData", "type": "object", - "required": [ - "func", - "wasmArtifact" - ], + "required": ["func", "wasmArtifact"], "properties": { "func": { "type": "string"