@isomorph.ai/app-sdk 1.6.0 → 1.6.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.
package/dist/index.js CHANGED
@@ -673,8 +673,11 @@ export function createClient(options = {}) {
673
673
  method: 'POST', body: JSON.stringify({ connection, operation, resource, ...(input !== undefined ? { input } : {}), ...(idempotencyKey !== undefined ? { idempotencyKey } : {}), ...(operation === 'slack.message.post' && mode !== undefined ? { mode } : {}) }),
674
674
  });
675
675
  },
676
+ // In a browser the consent returns the person to this page (without its
677
+ // fragment); governance accepts it only as a registered page of this app
678
+ // (ADR 0030). Outside a browser there is no page, and none is sent.
676
679
  connect: (connection) => transport.json('/_harbour/integrations/connect', {
677
- method: 'POST', body: JSON.stringify({ connection }),
680
+ method: 'POST', body: JSON.stringify({ connection, ...(typeof location !== 'undefined' && typeof location.href === 'string' ? { returnUrl: location.href.split('#')[0] } : {}) }),
678
681
  }),
679
682
  disconnect: (connection) => transport.json('/_harbour/integrations/connect', {
680
683
  method: 'DELETE', body: JSON.stringify({ connection }),
@@ -6,10 +6,16 @@
6
6
  // imported the app's client died exactly there (fourier smoke app, preview
7
7
  // 000006, 2026-09-21). An extensionless relative specifier is tried as the
8
8
  // `.ts` file, then as a folder's `index.ts`; anything else, and anything with
9
- // an extension, is left to Node.
9
+ // a module extension, is left to Node.
10
+ //
11
+ // "Extension" means a module extension, not any dot: the starter's client is
12
+ // `src/isomorph.client.ts`, and treating `.client` as an extension skipped the
13
+ // lookup, so the very import this hook exists for still failed (fourier
14
+ // app-06b08cba, beta preview 000001, 2026-09-29).
10
15
  import { access } from 'node:fs/promises';
11
16
  import { fileURLToPath } from 'node:url';
12
17
  const candidates = ['.ts', '.mts', '/index.ts'];
18
+ const moduleExtension = /\.(?:[cm]?[jt]s|[jt]sx|json|node|wasm)$/i;
13
19
  async function exists(url) {
14
20
  try {
15
21
  await access(fileURLToPath(url));
@@ -21,7 +27,7 @@ async function exists(url) {
21
27
  }
22
28
  export async function resolve(specifier, context, nextResolve) {
23
29
  const relative = specifier.startsWith('./') || specifier.startsWith('../');
24
- const extensionless = !/\.[A-Za-z0-9]+$/.test(specifier);
30
+ const extensionless = !moduleExtension.test(specifier);
25
31
  if (relative && extensionless && context.parentURL?.startsWith('file:')) {
26
32
  const base = new URL(specifier, context.parentURL).href;
27
33
  for (const suffix of candidates) {
package/dist/runtime.d.ts CHANGED
@@ -124,6 +124,7 @@ export declare class Runtime {
124
124
  */
125
125
  work(): Promise<boolean>;
126
126
  private serve;
127
+ private loadFailures;
127
128
  private reserved;
128
129
  }
129
130
  /** The runtime's settings from the environment; exported for the entry point and its test. */
package/dist/runtime.js CHANGED
@@ -535,12 +535,36 @@ export class Runtime {
535
535
  controller.abort();
536
536
  }
537
537
  }
538
+ // The gate's ping loads every actions/ and jobs/ module and names the ones
539
+ // that do not load. The actions journey only lists what the runtime serves
540
+ // (a builder's action needs an input the generator cannot invent), so an
541
+ // import that cannot resolve used to pass `isomorph check` and fail at the
542
+ // first click, hosted and in isomorph dev alike (fourier app-06b08cba,
543
+ // 2026-09-29). Ping still answers 200: the gate's readiness probe is ping.
544
+ // Messages are capped: the gate's coverage ledger parses the first 64 KiB.
545
+ async loadFailures() {
546
+ const failures = [];
547
+ const modules = [[ACTIONS_DIR, this.inventory.actions], [JOBS_DIR, this.inventory.jobs.map((job) => job.name)]];
548
+ for (const [dir, names] of modules) {
549
+ for (const name of names) {
550
+ try {
551
+ await loadHandler(this.options.root, dir, name);
552
+ }
553
+ catch (error) {
554
+ failures.push({ file: `${dir}/${name}.ts`, message: (error instanceof Error ? error.message : String(error)).slice(0, 500) });
555
+ }
556
+ }
557
+ }
558
+ return failures;
559
+ }
538
560
  async reserved(name, input, context) {
539
561
  const body = (input && typeof input === 'object' ? input : {});
540
562
  const owner = context.user.id;
541
563
  switch (name) {
542
- case PING_ACTION:
543
- return { ok: true, mode: this.options.mode, actions: this.inventory.actions, jobs: this.inventory.jobs.map((job) => job.name) };
564
+ case PING_ACTION: {
565
+ const answer = { ok: true, mode: this.options.mode, actions: this.inventory.actions, jobs: this.inventory.jobs.map((job) => job.name) };
566
+ return this.options.mode === 'gate' ? { ...answer, loadFailures: await this.loadFailures() } : answer;
567
+ }
544
568
  case ENQUEUE_ACTION: {
545
569
  const job = typeof body.name === 'string' ? body.name : '';
546
570
  if (!this.inventory.jobs.some((entry) => entry.name === job))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isomorph.ai/app-sdk",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",