@commercetools/cli-topic-integration-layer 0.0.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +64 -0
  3. package/dist/commands/integration-layer/config/get.d.ts +9 -0
  4. package/dist/commands/integration-layer/config/get.js +22 -0
  5. package/dist/commands/integration-layer/config/get.js.map +1 -0
  6. package/dist/commands/integration-layer/config/list.d.ts +6 -0
  7. package/dist/commands/integration-layer/config/list.js +20 -0
  8. package/dist/commands/integration-layer/config/list.js.map +1 -0
  9. package/dist/commands/integration-layer/config/set.d.ts +13 -0
  10. package/dist/commands/integration-layer/config/set.js +29 -0
  11. package/dist/commands/integration-layer/config/set.js.map +1 -0
  12. package/dist/commands/integration-layer/config/unset.d.ts +9 -0
  13. package/dist/commands/integration-layer/config/unset.js +18 -0
  14. package/dist/commands/integration-layer/config/unset.js.map +1 -0
  15. package/dist/commands/integration-layer/extension/build.d.ts +12 -0
  16. package/dist/commands/integration-layer/extension/build.js +40 -0
  17. package/dist/commands/integration-layer/extension/build.js.map +1 -0
  18. package/dist/commands/integration-layer/extension/delete.d.ts +9 -0
  19. package/dist/commands/integration-layer/extension/delete.js +39 -0
  20. package/dist/commands/integration-layer/extension/delete.js.map +1 -0
  21. package/dist/commands/integration-layer/extension/invoke.d.ts +13 -0
  22. package/dist/commands/integration-layer/extension/invoke.js +89 -0
  23. package/dist/commands/integration-layer/extension/invoke.js.map +1 -0
  24. package/dist/commands/integration-layer/extension/push.d.ts +28 -0
  25. package/dist/commands/integration-layer/extension/push.js +217 -0
  26. package/dist/commands/integration-layer/extension/push.js.map +1 -0
  27. package/dist/commands/integration-layer/extension/serve.d.ts +37 -0
  28. package/dist/commands/integration-layer/extension/serve.js +528 -0
  29. package/dist/commands/integration-layer/extension/serve.js.map +1 -0
  30. package/dist/commands/integration-layer/extension/status.d.ts +6 -0
  31. package/dist/commands/integration-layer/extension/status.js +28 -0
  32. package/dist/commands/integration-layer/extension/status.js.map +1 -0
  33. package/dist/commands/integration-layer/extension/validate.d.ts +15 -0
  34. package/dist/commands/integration-layer/extension/validate.js +98 -0
  35. package/dist/commands/integration-layer/extension/validate.js.map +1 -0
  36. package/dist/commands/integration-layer/hello.d.ts +6 -0
  37. package/dist/commands/integration-layer/hello.js +10 -0
  38. package/dist/commands/integration-layer/hello.js.map +1 -0
  39. package/dist/commands/integration-layer/init.d.ts +13 -0
  40. package/dist/commands/integration-layer/init.js +279 -0
  41. package/dist/commands/integration-layer/init.js.map +1 -0
  42. package/dist/commands/integration-layer/schema/fetch.d.ts +9 -0
  43. package/dist/commands/integration-layer/schema/fetch.js +27 -0
  44. package/dist/commands/integration-layer/schema/fetch.js.map +1 -0
  45. package/dist/index.d.ts +1 -0
  46. package/dist/index.js +5 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/lib/awaitBundleState.d.ts +33 -0
  49. package/dist/lib/awaitBundleState.js +77 -0
  50. package/dist/lib/awaitBundleState.js.map +1 -0
  51. package/dist/lib/base.d.ts +50 -0
  52. package/dist/lib/base.js +85 -0
  53. package/dist/lib/base.js.map +1 -0
  54. package/dist/lib/ilClient.d.ts +93 -0
  55. package/dist/lib/ilClient.js +120 -0
  56. package/dist/lib/ilClient.js.map +1 -0
  57. package/dist/lib/sourceRevision.d.ts +39 -0
  58. package/dist/lib/sourceRevision.js +95 -0
  59. package/dist/lib/sourceRevision.js.map +1 -0
  60. package/dist/lib/tooling/apiExtension.d.ts +31 -0
  61. package/dist/lib/tooling/apiExtension.js +39 -0
  62. package/dist/lib/tooling/apiExtension.js.map +1 -0
  63. package/dist/lib/tooling/build.d.ts +18 -0
  64. package/dist/lib/tooling/build.js +54 -0
  65. package/dist/lib/tooling/build.js.map +1 -0
  66. package/dist/lib/tooling/compose.d.ts +28 -0
  67. package/dist/lib/tooling/compose.js +48 -0
  68. package/dist/lib/tooling/compose.js.map +1 -0
  69. package/dist/lib/tooling/extensions.d.ts +77 -0
  70. package/dist/lib/tooling/extensions.js +209 -0
  71. package/dist/lib/tooling/extensions.js.map +1 -0
  72. package/dist/lib/tooling/gateway.d.ts +21 -0
  73. package/dist/lib/tooling/gateway.js +65 -0
  74. package/dist/lib/tooling/gateway.js.map +1 -0
  75. package/dist/lib/tooling/loadBundle.d.ts +10 -0
  76. package/dist/lib/tooling/loadBundle.js +27 -0
  77. package/dist/lib/tooling/loadBundle.js.map +1 -0
  78. package/dist/lib/tooling/staticAnalysis.d.ts +11 -0
  79. package/dist/lib/tooling/staticAnalysis.js +167 -0
  80. package/dist/lib/tooling/staticAnalysis.js.map +1 -0
  81. package/dist/lib/tooling/validateBundle.d.ts +19 -0
  82. package/dist/lib/tooling/validateBundle.js +144 -0
  83. package/dist/lib/tooling/validateBundle.js.map +1 -0
  84. package/package.json +47 -5
@@ -0,0 +1,98 @@
1
+ import { Flags } from "@oclif/core";
2
+ import { defaultEntry, defaultOutfile } from "../../../lib/tooling/build.js";
3
+ import { bundleForFlags } from "../../../lib/tooling/extensions.js";
4
+ import { validateBundle, BundleValidationError } from "../../../lib/tooling/validateBundle.js";
5
+ import { remoteValidate } from "../../../lib/ilClient.js";
6
+ import { IntegrationLayerCommand } from "../../../lib/base.js";
7
+ export default class ExtensionValidate extends IntegrationLayerCommand {
8
+ static description = "Build, run local checks, then compose against the project schema and gate breaking changes";
9
+ static examples = [
10
+ "<%= config.bin %> integration-layer extension validate",
11
+ "<%= config.bin %> integration-layer extension validate --skip remote",
12
+ "<%= config.bin %> integration-layer extension validate --all",
13
+ ];
14
+ static flags = {
15
+ entry: Flags.string({ description: "extension entry source file", default: defaultEntry() }),
16
+ out: Flags.string({ description: "bundle output file", default: defaultOutfile() }),
17
+ all: Flags.boolean({
18
+ description: "validate every extension under ./extensions/* merged into ONE combined bundle (the single deployed artifact)",
19
+ default: false,
20
+ }),
21
+ "extensions-dir": Flags.string({
22
+ description: "directory holding the extension packages (used with --all)",
23
+ default: "extensions",
24
+ }),
25
+ skip: Flags.string({
26
+ description: "run only one half of the gate",
27
+ options: ["local", "remote"],
28
+ }),
29
+ };
30
+ /** Print a remote validation result legibly. Returns true when it passed. */
31
+ reportRemote(result) {
32
+ if (!result.composes) {
33
+ this.logToStderr("✗ extension does not compose with the integration layer supergraph:");
34
+ for (const err of result.compositionErrors)
35
+ this.logToStderr(` - ${err}`);
36
+ return false;
37
+ }
38
+ if (result.breakingChanges.length > 0) {
39
+ this.logToStderr("✗ extension introduces breaking changes to the published supergraph:");
40
+ for (const change of result.breakingChanges) {
41
+ this.logToStderr(` - [${change.type}] ${change.description}`);
42
+ }
43
+ return false;
44
+ }
45
+ if (!result.comparedToPublished) {
46
+ this.log("✓ composes with the integration layer supergraph (breaking-change check skipped: no published baseline)");
47
+ return true;
48
+ }
49
+ this.log("✓ composes with the integration layer supergraph and introduces no breaking changes");
50
+ return true;
51
+ }
52
+ async run() {
53
+ const { flags } = await this.parse(ExtensionValidate);
54
+ let outfile;
55
+ let sourceFiles;
56
+ try {
57
+ ({ outfile, sourceFiles } = await bundleForFlags({
58
+ all: flags.all,
59
+ extensionsDir: flags["extensions-dir"],
60
+ entry: flags.entry,
61
+ out: flags.out,
62
+ }));
63
+ }
64
+ catch (err) {
65
+ this.error(err.message);
66
+ }
67
+ let typeDefs = null;
68
+ if (flags.skip !== "local") {
69
+ try {
70
+ const local = await validateBundle(outfile, sourceFiles);
71
+ typeDefs = local.typeDefs;
72
+ this.log(`✓ local checks passed (resolver roots: ${local.resolverTypes.join(", ") || "none"}; ` +
73
+ `API extensions: ${local.apiExtensionKeys.join(", ") || "none"})`);
74
+ }
75
+ catch (err) {
76
+ if (err instanceof BundleValidationError)
77
+ this.error(err.message);
78
+ throw err;
79
+ }
80
+ }
81
+ else {
82
+ // Skipping local: still need the SDL for the remote check — load it cheaply.
83
+ const local = await validateBundle(outfile, sourceFiles).catch(() => null);
84
+ typeDefs = local?.typeDefs ?? null;
85
+ }
86
+ if (flags.skip === "remote")
87
+ return;
88
+ if (typeDefs === null) {
89
+ this.log("· no GraphQL subgraph in this bundle — nothing to compose remotely.");
90
+ return;
91
+ }
92
+ const { baseUrl, projectKey, token } = await this.resolveIlContext(flags);
93
+ const result = await remoteValidate(baseUrl, projectKey, token, typeDefs);
94
+ if (!this.reportRemote(result))
95
+ this.error("remote validation failed.");
96
+ }
97
+ }
98
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/commands/integration-layer/extension/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class IntegrationLayerHelloCommand extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,10 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class IntegrationLayerHelloCommand extends Command {
3
+ static description = "Print a hello world message from the integration-layer topic";
4
+ static examples = ["<%= config.bin %> integration-layer hello"];
5
+ async run() {
6
+ await this.parse(IntegrationLayerHelloCommand);
7
+ this.log("Hello, world!");
8
+ }
9
+ }
10
+ //# sourceMappingURL=hello.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hello.js","sourceRoot":"","sources":["../../../src/commands/integration-layer/hello.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,MAAM,CAAC,OAAO,OAAO,4BAA6B,SAAQ,OAAO;IAC/D,MAAM,CAAU,WAAW,GAAG,8DAA8D,CAAC;IAE7F,MAAM,CAAU,QAAQ,GAAG,CAAC,2CAA2C,CAAC,CAAC;IAEzE,KAAK,CAAC,GAAG;QACP,MAAM,IAAI,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAC/C,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC5B,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { Command } from "@oclif/core";
2
+ export default class Init extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ directory: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ template: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,279 @@
1
+ import { mkdir, readdir, writeFile } from "node:fs/promises";
2
+ import { basename, join, resolve } from "node:path";
3
+ import { Args, Command, Flags } from "@oclif/core";
4
+ // `init` scaffolds a MONOREPO you own and grow — a pnpm workspace whose members are
5
+ // individual extensions (`extensions/*`), seeded with one buildable hello-world
6
+ // extension that extends `Query`. The build/validate/push flow itself lives in this
7
+ // published CLI plugin, not in the scaffold, so an extension package stays tiny (just
8
+ // `src/extension.ts` + a thin package.json/tsconfig). Everything is vendored inline —
9
+ // no network fetch — and kept dependency-light so the extension commands work on it
10
+ // out of the box. The `basic` template is the only one today.
11
+ /** Derive a valid npm package name from the scaffold directory (fallback: a generic one). */
12
+ function projectNameFor(dir) {
13
+ const sanitized = basename(resolve(dir))
14
+ .toLowerCase()
15
+ .replace(/[^a-z0-9-]+/g, "-")
16
+ .replace(/^-+|-+$/g, "");
17
+ return sanitized || "integration-layer-extensions";
18
+ }
19
+ /** The monorepo file set, parameterized by the root package name. */
20
+ function templateFiles(projectName) {
21
+ return {
22
+ "package.json": `{
23
+ "name": ${JSON.stringify(projectName)},
24
+ "private": true,
25
+ "type": "module",
26
+ "packageManager": "pnpm@11.17.0",
27
+ "engines": {
28
+ "node": "22.x || 24.x"
29
+ },
30
+ "scripts": {
31
+ "build": "commercetools integration-layer extension build --all",
32
+ "typecheck": "pnpm -r typecheck",
33
+ "lint": "eslint .",
34
+ "dev": "commercetools integration-layer extension serve --all",
35
+ "validate": "commercetools integration-layer extension validate --all",
36
+ "push": "commercetools integration-layer extension push --all"
37
+ },
38
+ "devDependencies": {
39
+ "eslint": "^10.8.0",
40
+ "typescript": "~6.0.3",
41
+ "typescript-eslint": "^8.65.0"
42
+ }
43
+ }
44
+ `,
45
+ "pnpm-workspace.yaml": `packages:
46
+ # Each extension is a workspace member (edit its src/extension.ts). A project deploys
47
+ # ONE bundle, so the root \`pnpm build\` / \`validate\` / \`push\` scripts MERGE every
48
+ # extension here into that single combined bundle — never one per package.
49
+ - 'extensions/*'
50
+
51
+ # Refuse dependency versions published less than 24h ago. Minutes; 1440 = 24h.
52
+ minimumReleaseAge: 1440
53
+ `,
54
+ "tsconfig.base.json": `{
55
+ "compilerOptions": {
56
+ "target": "ES2022",
57
+ "module": "NodeNext",
58
+ "moduleResolution": "NodeNext",
59
+ "strict": true,
60
+ "esModuleInterop": true,
61
+ "skipLibCheck": true,
62
+ "forceConsistentCasingInFileNames": true,
63
+ "resolveJsonModule": true
64
+ }
65
+ }
66
+ `,
67
+ "eslint.config.js": `import tseslint from 'typescript-eslint';
68
+
69
+ export default tseslint.config(
70
+ { ignores: ['**/dist/**', '**/node_modules/**'] },
71
+ ...tseslint.configs.recommended,
72
+ {
73
+ // Allow \`_\`-prefixed unused args (resolver signatures often ignore arguments).
74
+ files: ['**/*.ts'],
75
+ rules: {
76
+ '@typescript-eslint/no-unused-vars': [
77
+ 'error',
78
+ {
79
+ argsIgnorePattern: '^_',
80
+ varsIgnorePattern: '^_',
81
+ caughtErrorsIgnorePattern: '^_',
82
+ },
83
+ ],
84
+ },
85
+ },
86
+ );
87
+ `,
88
+ ".gitignore": `node_modules/
89
+ dist/
90
+ .env
91
+ `,
92
+ ".env.example": `# The authenticated commands (validate/push/status/delete, schema, config) reuse the
93
+ # token from \`commercetools auth login\` (as a manage_project client) — no credentials
94
+ # go here. Optionally override the integration-layer edge URL. Copy to .env.
95
+ INTEGRATION_LAYER_URL=
96
+ `,
97
+ "README.md": `# ${projectName}
98
+
99
+ A monorepo of commercetools integration-layer extensions, scaffolded by
100
+ \`commercetools integration-layer init\`. Each extension is a workspace member under
101
+ \`extensions/\`; the starter one (\`extensions/hello-world\`) adds a \`hello\` field to
102
+ \`Query\`.
103
+
104
+ A project deploys a **single bundle** — one federation subgraph the router composes
105
+ with the integration layer. So this repo's extensions are **merged into that one
106
+ bundle**: the root \`build\` / \`validate\` / \`push\` scripts combine everything under
107
+ \`extensions/\` and push it as one artifact (not one per package), and \`dev\` serves that
108
+ same merged subgraph locally. Split your code into as many \`extensions/*\` packages as
109
+ makes sense to author — they always ship as one.
110
+
111
+ ## Set up the CLI (once)
112
+
113
+ The \`build\`/\`serve\`/\`validate\`/\`push\` scripts run through the **commercetools CLI**'s
114
+ \`integration-layer\` topic, added by the published
115
+ \`@commercetools/cli-topic-integration-layer\` plugin. Install the CLI globally with
116
+ pnpm, add the plugin, then log in:
117
+
118
+ \`\`\`sh
119
+ # Install the commercetools CLI globally with pnpm, then add the integration-layer
120
+ # topic. The plugin is on the public npm registry, so no auth or scope mapping is
121
+ # needed. (Install from @dev for now — the \`plugins\` command is only in the CLI's dev
122
+ # prerelease; drop @dev once it ships to @latest.)
123
+ pnpm add -g @commercetools/cli@dev
124
+ commercetools plugins install @commercetools/cli-topic-integration-layer
125
+
126
+ # Log in once — mints the manage_project token the authenticated commands reuse
127
+ # (validate/push/status/delete, schema, config) and sets your target project.
128
+ commercetools auth login --project-key <your-project-key>
129
+ \`\`\`
130
+
131
+ ## Getting started
132
+
133
+ Everything runs through pnpm — the scripts below wrap the \`commercetools
134
+ integration-layer extension …\` commands.
135
+
136
+ \`\`\`sh
137
+ pnpm install
138
+
139
+ # From the repo root — these operate on the ONE combined bundle:
140
+ pnpm dev # merge every extension into one subgraph and serve it behind a local
141
+ # federated gateway (+ the integration layer) at
142
+ # http://localhost:4000/graphql — the production topology in miniature.
143
+ # Needs \`commercetools auth login\` (composes against your live schema).
144
+ pnpm validate # compose the combined bundle against the live schema (no upload)
145
+ pnpm push # validate + upload the combined bundle (replaces the project's one)
146
+
147
+ # …or focus on a single extension in isolation (standalone subgraph, no login needed):
148
+ pnpm --filter @extensions/hello-world dev
149
+ \`\`\`
150
+
151
+ With \`pnpm dev\` running, open http://localhost:4000/graphql for a GraphiQL over the
152
+ merged schema; the raw combined extensions subgraph is at \`/_extension\`, and the
153
+ browsable merged (extensions + integration layer) schema at \`/composed\`.
154
+
155
+ Optionally copy \`.env.example\` to \`.env\` to override the integration-layer edge URL.
156
+
157
+ ## Adding another extension
158
+
159
+ Copy \`extensions/hello-world\` to \`extensions/<your-extension>\`, rename it in its
160
+ \`package.json\`, and edit its \`src/extension.ts\`. The root scripts discover every folder
161
+ under \`extensions/\` automatically and merge it into the single bundle — so \`pnpm dev\`,
162
+ \`validate\`, and \`push\` all just pick it up, with no port wrangling. (Two extensions
163
+ can each add fields to \`Query\`; they only clash if they declare the *same* field.)
164
+ `,
165
+ "extensions/hello-world/package.json": `{
166
+ "name": "@extensions/hello-world",
167
+ "version": "0.1.0",
168
+ "private": true,
169
+ "type": "module",
170
+ "scripts": {
171
+ "build": "commercetools integration-layer extension build",
172
+ "dev": "commercetools integration-layer extension serve",
173
+ "typecheck": "tsc --noEmit"
174
+ },
175
+ "devDependencies": {
176
+ "@types/node": "^22.20.1",
177
+ "typescript": "~6.0.3"
178
+ }
179
+ }
180
+ `,
181
+ "extensions/hello-world/tsconfig.json": `{
182
+ "extends": "../../tsconfig.base.json",
183
+ "compilerOptions": {
184
+ "noEmit": true,
185
+ "types": ["node"]
186
+ },
187
+ "include": ["src"],
188
+ "exclude": ["node_modules", "dist"]
189
+ }
190
+ `,
191
+ "extensions/hello-world/src/extension.ts": `/**
192
+ * A hello-world integration-layer extension — the PURELY ADDITIVE pattern: it adds a
193
+ * brand-new root field (\`Query.hello\`) and shares nothing with the integration layer,
194
+ * so the two \`Query\` types merge with no change to it and composition is trivial.
195
+ *
196
+ * An extension exports \`typeDefs\` (a federation-v2 SDL string) + \`resolvers\` and runs
197
+ * in a restricted runtime. Edit this file, then from the repo ROOT run \`pnpm validate\` /
198
+ * \`pnpm push\` — every extension is merged into the one bundle the project deploys (the
199
+ * target project comes from your \`commercetools auth login\`). Iterate on just this one
200
+ * with \`pnpm --filter @extensions/hello-world dev\`.
201
+ */
202
+
203
+ export const typeDefs = \`
204
+ extend schema @link(url: "https://specs.apollo.dev/federation/v2.3")
205
+
206
+ type Query {
207
+ "A friendly greeting contributed by this extension."
208
+ hello(name: String): String!
209
+ }
210
+ \`;
211
+
212
+ /**
213
+ * The per-call capability context the restricted runtime hands each resolver.
214
+ * \`now()\` is the current epoch millis (a convenience — \`Date.now()\` works too);
215
+ * \`config\` is this extension's merchant-supplied \`{ key: value }\` map, with secret
216
+ * values decrypted host-side (e.g. \`ctx.config.API_KEY\`). Set values with
217
+ * \`commercetools integration-layer config set <KEY> <VALUE>\`.
218
+ */
219
+ interface ExtensionContext {
220
+ now(): number;
221
+ config: Readonly<Record<string, string>>;
222
+ }
223
+
224
+ export const resolvers = {
225
+ Query: {
226
+ // A resolver receives (parent, args, context): \`_parent\` is the object the field
227
+ // hangs off (nothing here — this is a root field), \`args\` are the field arguments
228
+ // from the query, and \`ctx\` exposes the restricted runtime's host capabilities.
229
+ hello: (_parent: unknown, { name }: { name?: string }, ctx: ExtensionContext) => {
230
+ const greeting = ctx.config.GREETING ?? "Hello";
231
+ return \`\${greeting}, \${name ?? "world"}, from your integration-layer extension!\`;
232
+ },
233
+ },
234
+ };
235
+ `,
236
+ };
237
+ }
238
+ export default class Init extends Command {
239
+ static description = "Scaffold an integration-layer extensions monorepo (a pnpm workspace with one hello-world extension)";
240
+ static examples = [
241
+ "<%= config.bin %> integration-layer init my-extensions",
242
+ "<%= config.bin %> integration-layer init my-extensions --template basic",
243
+ ];
244
+ static args = {
245
+ directory: Args.string({ description: "directory to scaffold the monorepo into", required: true }),
246
+ };
247
+ static flags = {
248
+ template: Flags.string({
249
+ description: "the template to use",
250
+ options: ["basic"],
251
+ default: "basic",
252
+ }),
253
+ force: Flags.boolean({
254
+ char: "f",
255
+ description: "scaffold into a non-empty directory",
256
+ default: false,
257
+ }),
258
+ };
259
+ async run() {
260
+ const { args, flags } = await this.parse(Init);
261
+ const dir = args.directory;
262
+ const existing = await readdir(dir).catch(() => []);
263
+ if (existing.length > 0 && !flags.force) {
264
+ this.error(`Directory '${dir}' is not empty. Pass --force to scaffold into it anyway.`);
265
+ }
266
+ const files = templateFiles(projectNameFor(dir));
267
+ for (const [relPath, contents] of Object.entries(files)) {
268
+ const target = join(dir, relPath);
269
+ await mkdir(join(target, ".."), { recursive: true });
270
+ await writeFile(target, contents, "utf8");
271
+ }
272
+ this.log(`✓ scaffolded a '${flags.template}' extensions monorepo in ${dir}`);
273
+ this.log("Next steps:");
274
+ this.log(` cd ${dir}`);
275
+ this.log(" pnpm install");
276
+ this.log(" pnpm dev # run the hello-world extension locally");
277
+ }
278
+ }
279
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/commands/integration-layer/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { IntegrationLayerCommand } from "../../../lib/base.js";
2
+ export default class SchemaFetch extends IntegrationLayerCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ out: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,27 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { Flags } from "@oclif/core";
3
+ import { fetchSubgraphSdl } from "../../../lib/ilClient.js";
4
+ import { IntegrationLayerCommand } from "../../../lib/base.js";
5
+ export default class SchemaFetch extends IntegrationLayerCommand {
6
+ static description = "Print (or write) the project's core-subgraph SDL — the input extensions compose against";
7
+ static examples = [
8
+ "<%= config.bin %> integration-layer schema fetch",
9
+ "<%= config.bin %> integration-layer schema fetch --out subgraph.graphql",
10
+ ];
11
+ static flags = {
12
+ out: Flags.string({ description: "write the SDL to this file instead of stdout" }),
13
+ };
14
+ async run() {
15
+ const { flags } = await this.parse(SchemaFetch);
16
+ const { baseUrl, projectKey, token } = await this.resolveIlContext(flags);
17
+ const sdl = await fetchSubgraphSdl(baseUrl, projectKey, token);
18
+ if (flags.out) {
19
+ await writeFile(flags.out, sdl, "utf8");
20
+ this.log(`✓ wrote ${projectKey} core-subgraph SDL → ${flags.out}`);
21
+ }
22
+ else {
23
+ this.log(sdl);
24
+ }
25
+ }
26
+ }
27
+ //# sourceMappingURL=fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../../../src/commands/integration-layer/schema/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,uBAAuB;IAC9D,MAAM,CAAU,WAAW,GACzB,yFAAyF,CAAC;IAE5F,MAAM,CAAU,QAAQ,GAAG;QACzB,kDAAkD;QAClD,yEAAyE;KAC1E,CAAC;IAEF,MAAM,CAAU,KAAK,GAAG;QACtB,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,8CAA8C,EAAE,CAAC;KACnF,CAAC;IAEF,KAAK,CAAC,GAAG;QACP,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAChD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC1E,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QAC/D,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;YACd,MAAM,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YACxC,IAAI,CAAC,GAAG,CAAC,WAAW,UAAU,wBAAwB,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QACrE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC;IACH,CAAC"}
@@ -0,0 +1 @@
1
+ export { defineApiExtension, approve, block, update, type ApiExtensionAction, type ApiExtensionDefinition, type ApiExtensionError, type ApiExtensionInput, type ApiExtensionResult, type ExtensionContext, type ExtensionInput, } from "./lib/tooling/apiExtension.js";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // oclif discovers commands from the `oclif.commands` directory (see package.json).
2
+ // The package `main` re-exports the extension authoring API so an author can import
3
+ // the helpers/types when writing `src/extension.ts`.
4
+ export { defineApiExtension, approve, block, update, } from "./lib/tooling/apiExtension.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,oFAAoF;AACpF,qDAAqD;AACrD,OAAO,EACL,kBAAkB,EAClB,OAAO,EACP,KAAK,EACL,MAAM,GAQP,MAAM,+BAA+B,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { type ExtensionMeta } from "./ilClient.js";
2
+ /** How the wait ended. Only `failed` means "the push produced a broken bundle". */
3
+ export type BundleOutcome = {
4
+ kind: "running";
5
+ meta: ExtensionMeta;
6
+ } | {
7
+ kind: "failed";
8
+ meta: ExtensionMeta;
9
+ } | {
10
+ kind: "superseded";
11
+ meta: ExtensionMeta;
12
+ } | {
13
+ kind: "unknown";
14
+ reason: string;
15
+ meta?: ExtensionMeta;
16
+ };
17
+ export interface AwaitOptions {
18
+ /** Give up after this long. */
19
+ timeoutMs: number;
20
+ /** Gap between metadata reads. */
21
+ intervalMs: number;
22
+ /** Injected so tests don't actually sleep. */
23
+ sleep?: (ms: number) => Promise<void>;
24
+ /** Injected so tests control elapsed time. */
25
+ now?: () => number;
26
+ }
27
+ /**
28
+ * Poll until `version` leaves `pending`, or we run out of time.
29
+ *
30
+ * The first read happens immediately — an extension that was already mid-poll can
31
+ * settle the version before we ever sleep.
32
+ */
33
+ export declare function awaitBundleState(baseUrl: string, projectKey: string, token: string, version: number, options: AwaitOptions): Promise<BundleOutcome>;
@@ -0,0 +1,77 @@
1
+ // Wait for a just-pushed bundle version to prove itself.
2
+ //
3
+ // A push only STORES a bundle. The extension picks it up on its own poll, tries to
4
+ // load it, and reports back — so the version starts `pending` and only becomes
5
+ // `running` (it loaded and published its schema) or `failed` (it didn't, with a
6
+ // reason) a little later. Until this, `push` reported success the moment the bytes
7
+ // landed, which meant a bundle the sandbox refuses to run looked like a clean push.
8
+ //
9
+ // This polls the project's bundle metadata until the pushed version settles, and
10
+ // hands the caller back an outcome it can turn into an exit code.
11
+ //
12
+ // Three things it deliberately does NOT do:
13
+ //
14
+ // - It never treats "I couldn't find out" as a failure. An integration layer that
15
+ // predates bundle state reports no `state` at all, and a project whose extension
16
+ // isn't deployed yet will never move off `pending`. Both are `unknown`, not
17
+ // `failed` — failing a push for them would break perfectly good workflows.
18
+ // - It doesn't watch for the version to change under it. If someone else pushes
19
+ // while we wait, the newest version is no longer ours; we say so and stop rather
20
+ // than report on somebody else's push.
21
+ // - It doesn't retry transient metadata-read errors into a verdict. A read that
22
+ // throws ends the wait as `unknown` with the error attached.
23
+ import { fetchExtensionMeta } from "./ilClient.js";
24
+ const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
25
+ /**
26
+ * Poll until `version` leaves `pending`, or we run out of time.
27
+ *
28
+ * The first read happens immediately — an extension that was already mid-poll can
29
+ * settle the version before we ever sleep.
30
+ */
31
+ export async function awaitBundleState(baseUrl, projectKey, token, version, options) {
32
+ const sleep = options.sleep ?? defaultSleep;
33
+ const now = options.now ?? Date.now;
34
+ const deadline = now() + options.timeoutMs;
35
+ for (;;) {
36
+ let meta;
37
+ try {
38
+ meta = await fetchExtensionMeta(baseUrl, projectKey, token);
39
+ }
40
+ catch (err) {
41
+ return {
42
+ kind: "unknown",
43
+ reason: `could not read the stored bundle's status: ${err.message}`,
44
+ };
45
+ }
46
+ if (meta === null) {
47
+ // Deleted out from under us between the push and this read.
48
+ return { kind: "unknown", reason: "no bundle is stored for this project any more" };
49
+ }
50
+ if (meta.state === undefined) {
51
+ // An integration layer that doesn't report state. Nothing to wait for.
52
+ return {
53
+ kind: "unknown",
54
+ reason: "this integration layer does not report bundle status",
55
+ meta,
56
+ };
57
+ }
58
+ if (meta.version !== version) {
59
+ // Someone else pushed while we were waiting; the newest version isn't ours.
60
+ return { kind: "superseded", meta };
61
+ }
62
+ if (meta.state === "running")
63
+ return { kind: "running", meta };
64
+ if (meta.state === "failed")
65
+ return { kind: "failed", meta };
66
+ // Still pending.
67
+ if (now() >= deadline) {
68
+ return {
69
+ kind: "unknown",
70
+ reason: `the extension did not report on version ${version} within ${Math.round(options.timeoutMs / 1000)}s`,
71
+ meta,
72
+ };
73
+ }
74
+ await sleep(options.intervalMs);
75
+ }
76
+ }
77
+ //# sourceMappingURL=awaitBundleState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"awaitBundleState.js","sourceRoot":"","sources":["../../src/lib/awaitBundleState.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,EAAE;AACF,mFAAmF;AACnF,+EAA+E;AAC/E,gFAAgF;AAChF,mFAAmF;AACnF,oFAAoF;AACpF,EAAE;AACF,iFAAiF;AACjF,kEAAkE;AAClE,EAAE;AACF,4CAA4C;AAC5C,EAAE;AACF,oFAAoF;AACpF,qFAAqF;AACrF,gFAAgF;AAChF,+EAA+E;AAC/E,kFAAkF;AAClF,qFAAqF;AACrF,2CAA2C;AAC3C,kFAAkF;AAClF,iEAAiE;AAEjE,OAAO,EAAE,kBAAkB,EAAsB,MAAM,eAAe,CAAC;AAoBvE,MAAM,YAAY,GAAG,CAAC,EAAU,EAAiB,EAAE,CACjD,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAe,EACf,UAAkB,EAClB,KAAa,EACb,OAAe,EACf,OAAqB;IAErB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC;IAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,MAAM,QAAQ,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC;IAE3C,SAAS,CAAC;QACR,IAAI,IAA0B,CAAC;QAC/B,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,8CAA+C,GAAa,CAAC,OAAO,EAAE;aAC/E,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,4DAA4D;YAC5D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,+CAA+C,EAAE,CAAC;QACtF,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC7B,uEAAuE;YACvE,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,sDAAsD;gBAC9D,IAAI;aACL,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAC7B,4EAA4E;YAC5E,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QACtC,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC/D,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAE7D,iBAAiB;QACjB,IAAI,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC;YACtB,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,2CAA2C,OAAO,WAAW,IAAI,CAAC,KAAK,CAC7E,OAAO,CAAC,SAAS,GAAG,IAAI,CACzB,GAAG;gBACJ,IAAI;aACL,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC;AACH,CAAC"}