@isomorph.ai/app-sdk 1.13.0 → 1.13.2-rc.2026101101
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/README.md +4 -0
- package/dist/index.d.ts +6 -1
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +19 -1
- package/dist/supabase-compat.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -183,6 +183,10 @@ and no second GET is sent. When the refresh fails, `identity.current()`
|
|
|
183
183
|
answers `null` and listeners hear `null`, as before. On the page's own origin
|
|
184
184
|
the identity GET is never renewed (it is the renewal). (1.5.3)
|
|
185
185
|
|
|
186
|
+
## External OTP users
|
|
187
|
+
|
|
188
|
+
Use `user.id` for ownership and database row rules. External users can sign in with a phone number and have no email. `user.name`, `user.phone`, `user.email` and the `emailVerified`/`phoneVerified` flags describe their profile; an optional contact is not verified automatically. `user.directory` identifies `company` or `external`. Database transactions also expose `current_setting('harbour.directory', true)` when a row rule needs that distinction.
|
|
189
|
+
|
|
186
190
|
## The signed-in user's groups
|
|
187
191
|
|
|
188
192
|
`user.groups` — the company groups your identity provider sent at sign-in; use
|
package/dist/index.d.ts
CHANGED
|
@@ -13,7 +13,12 @@ export declare class IsomorphError extends Error {
|
|
|
13
13
|
}
|
|
14
14
|
export interface IsomorphUser {
|
|
15
15
|
id: string;
|
|
16
|
-
email
|
|
16
|
+
email?: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
phone?: string;
|
|
19
|
+
directory?: 'company' | 'external';
|
|
20
|
+
emailVerified?: boolean;
|
|
21
|
+
phoneVerified?: boolean;
|
|
17
22
|
/**
|
|
18
23
|
* The company groups your identity provider sent at sign-in, `[]` when it
|
|
19
24
|
* sent none. Use them for in-app roles: who may open the app at all is
|
package/dist/runtime.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export declare const GET_RUN_ACTION = "isomorph-jobs-get";
|
|
|
11
11
|
export declare const CANCEL_RUN_ACTION = "isomorph-jobs-cancel";
|
|
12
12
|
export interface ActionContext {
|
|
13
13
|
signal: AbortSignal;
|
|
14
|
-
user:
|
|
14
|
+
user: IsomorphUser;
|
|
15
15
|
tenant: string;
|
|
16
16
|
app: string;
|
|
17
17
|
requestId: string;
|
package/dist/runtime.js
CHANGED
|
@@ -54,6 +54,7 @@ import { createServer } from 'node:http';
|
|
|
54
54
|
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
55
55
|
import { register } from 'node:module';
|
|
56
56
|
import { join, resolve } from 'node:path';
|
|
57
|
+
import { realpathSync } from 'node:fs';
|
|
57
58
|
import { pathToFileURL } from 'node:url';
|
|
58
59
|
import { createClient, IsomorphError } from './index.js';
|
|
59
60
|
import { userGroupsFromHeader } from './user-groups.js';
|
|
@@ -488,11 +489,16 @@ export class Runtime {
|
|
|
488
489
|
const controller = new AbortController();
|
|
489
490
|
const abort = () => controller.abort();
|
|
490
491
|
response.once('close', abort);
|
|
492
|
+
const directory = header(request, 'X-Harbour-Verified-Directory');
|
|
491
493
|
const user = {
|
|
492
494
|
id: header(request, 'X-Harbour-Verified-User-ID'),
|
|
493
495
|
email: header(request, 'X-Harbour-Verified-User-Email'),
|
|
494
496
|
groups: userGroupsFromHeader(header(request, 'X-Harbour-Verified-User-Groups')),
|
|
495
497
|
role: userRole(header(request, 'X-Harbour-Verified-User-Role')),
|
|
498
|
+
...(directory === 'company' || directory === 'external' ? { directory } : {}),
|
|
499
|
+
...(header(request, 'X-Harbour-Verified-User-Name') ? { name: header(request, 'X-Harbour-Verified-User-Name') } : {}),
|
|
500
|
+
...(header(request, 'X-Harbour-Verified-User-Phone') ? { phone: header(request, 'X-Harbour-Verified-User-Phone') } : {}),
|
|
501
|
+
...(directory === 'external' ? { emailVerified: header(request, 'X-Harbour-Verified-Email-Verified') === 'true', phoneVerified: header(request, 'X-Harbour-Verified-Phone-Verified') === 'true' } : {}),
|
|
496
502
|
};
|
|
497
503
|
const streams = header(request, 'accept').toLowerCase().includes(PROGRESS_MEDIA_TYPE);
|
|
498
504
|
let steps = 0;
|
|
@@ -629,7 +635,19 @@ export function runJobFromArguments(argv = process.argv.slice(2)) {
|
|
|
629
635
|
}
|
|
630
636
|
return undefined;
|
|
631
637
|
}
|
|
632
|
-
|
|
638
|
+
// Node resolves this module's URL through any symlink in its path, while
|
|
639
|
+
// process.argv[1] is the path the starter typed. On macOS /tmp and /var are
|
|
640
|
+
// symlinks, so a gate or `isomorph dev` started from an app root under them
|
|
641
|
+
// handed a path whose URL never matched, and the runtime loaded as a library
|
|
642
|
+
// and exited 0 without a word (the gate reported "exited before it
|
|
643
|
+
// answered", 2026-10-06). Compare the real path, as Node did.
|
|
644
|
+
const entryPath = process.argv[1] ? (() => { try {
|
|
645
|
+
return realpathSync(process.argv[1]);
|
|
646
|
+
}
|
|
647
|
+
catch {
|
|
648
|
+
return process.argv[1];
|
|
649
|
+
} })() : '';
|
|
650
|
+
const entry = entryPath ? pathToFileURL(entryPath).href : '';
|
|
633
651
|
if (import.meta.url === entry) {
|
|
634
652
|
// Extensionless relative imports in the app's server code resolve to
|
|
635
653
|
// their .ts files (runtime-hooks.ts); registered before any app module
|
|
@@ -130,7 +130,7 @@ export declare class SupabaseCompatQueryBuilder<T, Result = T[], Head extends bo
|
|
|
130
130
|
}
|
|
131
131
|
export interface SupabaseCompatUser {
|
|
132
132
|
id: string;
|
|
133
|
-
email
|
|
133
|
+
email?: string;
|
|
134
134
|
app_metadata: Record<string, unknown>;
|
|
135
135
|
/** Isomorph's per-app user record (`IsomorphUser.appUser`) when it is an object. */
|
|
136
136
|
user_metadata: Record<string, unknown>;
|