@comfyorg/account-core 1.0.0-alpha.0 → 1.0.0-alpha.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/core/billing/billingContracts.d.ts +29 -14
- package/dist/core/billing/billingErrorBody.d.ts +8 -4
- package/dist/core/billing/billingErrorBody.js +14 -4
- package/dist/core/billing/credentialedTransport.d.ts +23 -7
- package/dist/core/billing/credentialedTransport.js +72 -8
- package/dist/core/billing/events.d.ts +47 -0
- package/dist/core/billing/events.js +43 -0
- package/dist/core/billing/index.d.ts +16 -11
- package/dist/core/billing/index.js +8 -6
- package/dist/core/billing/operationLifecycle.d.ts +34 -1
- package/dist/core/billing/operationLifecycle.js +146 -67
- package/dist/core/billing/operationPointer.d.ts +27 -2
- package/dist/core/billing/operationPointer.js +36 -25
- package/dist/core/billing/operationPolicy.d.ts +44 -7
- package/dist/core/billing/operationPolicy.js +64 -3
- package/dist/core/billing/operationState.d.ts +225 -19
- package/dist/core/billing/operationState.js +93 -8
- package/dist/core/billing/paymentCopy.d.ts +6 -1
- package/dist/core/billing/paymentCopy.js +34 -1
- package/dist/core/billing/paymentProjection.d.ts +14 -2
- package/dist/core/billing/paymentProjection.js +37 -9
- package/dist/core/billing/scopedReader.d.ts +11 -5
- package/dist/core/billing/scopedReader.js +20 -9
- package/dist/core/billing/sharedRead.js +4 -2
- package/dist/core/billing/subscriptionCommands.d.ts +63 -9
- package/dist/core/billing/subscriptionCommands.js +46 -30
- package/dist/core/billing/topup.d.ts +26 -0
- package/dist/core/billing/topup.js +36 -2
- package/dist/core/billing/wireCents.d.ts +8 -0
- package/dist/core/billing/wireCents.js +8 -0
- package/dist/core/billing/workspaceInvites.d.ts +12 -0
- package/dist/core/billing/workspaceInvites.js +26 -0
- package/dist/core/identity.d.ts +6 -6
- package/dist/core/identity.js +4 -10
- package/dist/core/lazyIdentity.d.ts +31 -0
- package/dist/core/lazyIdentity.js +96 -0
- package/dist/core/requestAuth.d.ts +30 -0
- package/dist/core/requestAuth.js +41 -0
- package/dist/core/requestTimeout.d.ts +7 -0
- package/dist/core/requestTimeout.js +13 -0
- package/dist/core/session.d.ts +12 -18
- package/dist/core/session.js +16 -26
- package/dist/core/sessionContracts.d.ts +39 -2
- package/dist/core/sessionTokenMint.d.ts +35 -0
- package/dist/core/sessionTokenMint.js +222 -0
- package/dist/core/webSession.d.ts +27 -0
- package/dist/core/webSession.js +144 -0
- package/dist/core/webSessionFlag.d.ts +19 -0
- package/dist/core/webSessionFlag.js +61 -0
- package/dist/core/webSessionIdentity.d.ts +297 -0
- package/dist/core/webSessionIdentity.js +509 -0
- package/dist/firebase/configSource.d.ts +54 -0
- package/dist/firebase/configSource.js +111 -0
- package/dist/firebase/index.d.ts +71 -8
- package/dist/firebase/index.js +236 -23
- package/dist/firebase/popupWatch.d.ts +42 -0
- package/dist/firebase/popupWatch.js +140 -0
- package/dist/testing.d.ts +38 -0
- package/dist/testing.js +116 -0
- package/dist/web/crossTabRefresh.d.ts +4 -2
- package/dist/web/crossTabRefresh.js +13 -0
- package/dist/workspaceLink.d.ts +45 -0
- package/dist/workspaceLink.js +78 -0
- package/package.json +30 -6
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The session-backed identity source: boots a site from `GET /auth/session`
|
|
3
|
+
* and follows the server's answer. It keeps no record of past sessions, and
|
|
4
|
+
* the remembered provider login is an opaque port, so no provider leaks in.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import type { CrossTabRefreshPort, WebSession, WebSessionCommandResult, WebSessionResult } from './sessionContracts.js';
|
|
8
|
+
import type { WebSessionOptions } from './webSession.js';
|
|
9
|
+
export interface RememberedLogin {
|
|
10
|
+
/** The Comfy user id of the login this browser remembers, or null. */
|
|
11
|
+
currentUserId: () => Promise<string | null>;
|
|
12
|
+
/** Null when the provider has no usable login; a throw is transient. */
|
|
13
|
+
getProof: () => Promise<string | null>;
|
|
14
|
+
signOutLocally: () => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export type WebSessionPrincipal = {
|
|
17
|
+
readonly kind: 'account';
|
|
18
|
+
readonly rememberedLogin: RememberedLogin;
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: 'api_key';
|
|
21
|
+
};
|
|
22
|
+
export type WebSessionBootOutcome = 'signed_in' | 'restored' | 'signed_out' | 'revoked' | 'restore_failed';
|
|
23
|
+
export interface WebSessionBootstrapEvent {
|
|
24
|
+
readonly outcome: WebSessionBootOutcome;
|
|
25
|
+
readonly origin: string;
|
|
26
|
+
}
|
|
27
|
+
type SignedOutOutcome = Exclude<WebSessionBootOutcome, 'signed_in' | 'restored'>;
|
|
28
|
+
/** The account this tab holds changed under it, or went away. */
|
|
29
|
+
export type WebSessionAccountChange = {
|
|
30
|
+
readonly reason: 'user_changed';
|
|
31
|
+
readonly session: WebSession;
|
|
32
|
+
} | {
|
|
33
|
+
readonly reason: 'signed_out';
|
|
34
|
+
readonly outcome: SignedOutOutcome;
|
|
35
|
+
};
|
|
36
|
+
export type WebSessionIdentityState = {
|
|
37
|
+
readonly phase: 'idle';
|
|
38
|
+
} | {
|
|
39
|
+
readonly phase: 'api_key';
|
|
40
|
+
} | {
|
|
41
|
+
readonly phase: 'reading' | 'retry_wait' | 'restoring';
|
|
42
|
+
readonly failures: number;
|
|
43
|
+
} | {
|
|
44
|
+
readonly phase: 'signed_in';
|
|
45
|
+
readonly session: WebSession;
|
|
46
|
+
} | {
|
|
47
|
+
readonly phase: 'signed_out';
|
|
48
|
+
readonly outcome: SignedOutOutcome;
|
|
49
|
+
};
|
|
50
|
+
/** Only a sibling's sign-in is news to a tab that has signed out. */
|
|
51
|
+
export type SessionObservedFrom = 'this_tab' | 'sibling_heartbeat' | 'sibling_sign_in' | 'sibling_sign_out';
|
|
52
|
+
export type WebSessionIdentityEvent = {
|
|
53
|
+
readonly type: 'boot';
|
|
54
|
+
} | {
|
|
55
|
+
readonly type: 'read_answered' | 'restore_answered';
|
|
56
|
+
readonly result: WebSessionResult;
|
|
57
|
+
readonly rememberedUserId: string | null;
|
|
58
|
+
} | {
|
|
59
|
+
readonly type: 'proof_missing' | 'proof_errored' | 'login_errored';
|
|
60
|
+
} | {
|
|
61
|
+
readonly type: 'retry_due';
|
|
62
|
+
}
|
|
63
|
+
/** A heartbeat answer, this tab's or one a sibling tab published. */
|
|
64
|
+
| {
|
|
65
|
+
readonly type: 'session_observed';
|
|
66
|
+
readonly from: SessionObservedFrom;
|
|
67
|
+
readonly result: WebSessionResult;
|
|
68
|
+
readonly rememberedUserId: string | null;
|
|
69
|
+
} | {
|
|
70
|
+
readonly type: 'session_created';
|
|
71
|
+
readonly session: WebSession;
|
|
72
|
+
} | {
|
|
73
|
+
readonly type: 'sign_out_requested';
|
|
74
|
+
};
|
|
75
|
+
export type WebSessionIdentityEffect = {
|
|
76
|
+
readonly type: 'read';
|
|
77
|
+
} | {
|
|
78
|
+
readonly type: 'restore';
|
|
79
|
+
readonly expectedUserId: string;
|
|
80
|
+
} | {
|
|
81
|
+
readonly type: 'schedule_retry';
|
|
82
|
+
readonly failures: number;
|
|
83
|
+
} | {
|
|
84
|
+
readonly type: 'sign_out_locally';
|
|
85
|
+
} | {
|
|
86
|
+
readonly type: 'report';
|
|
87
|
+
readonly outcome: WebSessionBootOutcome;
|
|
88
|
+
} | {
|
|
89
|
+
readonly type: 'account_changed';
|
|
90
|
+
readonly change: WebSessionAccountChange;
|
|
91
|
+
} | {
|
|
92
|
+
readonly type: 'report_signed_out_remotely';
|
|
93
|
+
};
|
|
94
|
+
export interface WebSessionIdentityTransition {
|
|
95
|
+
readonly state: WebSessionIdentityState;
|
|
96
|
+
readonly effects: readonly WebSessionIdentityEffect[];
|
|
97
|
+
}
|
|
98
|
+
/** Pure: an event that means nothing in the current phase changes nothing. */
|
|
99
|
+
export declare function transitionWebSessionIdentity(state: WebSessionIdentityState, event: WebSessionIdentityEvent): WebSessionIdentityTransition;
|
|
100
|
+
export type ScheduleRetry = (run: () => void, delayMs: number) => () => void;
|
|
101
|
+
export interface VisibilityPort {
|
|
102
|
+
isVisible: () => boolean;
|
|
103
|
+
onChange: (listener: (visible: boolean) => void) => () => void;
|
|
104
|
+
}
|
|
105
|
+
export interface WebSessionHeartbeatOptions {
|
|
106
|
+
readonly visibility: VisibilityPort;
|
|
107
|
+
/** Without it every tab reads for itself. */
|
|
108
|
+
readonly crossTab?: CrossTabRefreshPort<WebSessionSharedMessage>;
|
|
109
|
+
readonly intervalMs?: number;
|
|
110
|
+
}
|
|
111
|
+
export interface WebSessionIdentityOptions {
|
|
112
|
+
readonly session: WebSessionOptions;
|
|
113
|
+
readonly principal: WebSessionPrincipal;
|
|
114
|
+
/** The site reporting the boot, e.g. `https://www.comfy.org`. */
|
|
115
|
+
readonly origin: string;
|
|
116
|
+
readonly onBootstrap?: (event: WebSessionBootstrapEvent) => void;
|
|
117
|
+
/** Telemetry for `session_signed_out_remotely`. */
|
|
118
|
+
readonly onSignedOutRemotely?: (event: {
|
|
119
|
+
readonly origin: string;
|
|
120
|
+
}) => void;
|
|
121
|
+
/** The host drops pending actions and user-scoped state here. */
|
|
122
|
+
readonly onAccountChanged?: (change: WebSessionAccountChange & {
|
|
123
|
+
readonly epoch: number;
|
|
124
|
+
}) => void;
|
|
125
|
+
readonly heartbeat?: WebSessionHeartbeatOptions;
|
|
126
|
+
readonly schedule?: ScheduleRetry;
|
|
127
|
+
readonly retryBaseMs?: number;
|
|
128
|
+
readonly retryMaxMs?: number;
|
|
129
|
+
}
|
|
130
|
+
export interface WebSessionIdentity {
|
|
131
|
+
getState: () => WebSessionIdentityState;
|
|
132
|
+
/** Delivers the current state at once, then every change. */
|
|
133
|
+
subscribe: (listener: (state: WebSessionIdentityState) => void) => () => void;
|
|
134
|
+
/** Starts the boot and the heartbeat; a no-op unless idle. */
|
|
135
|
+
boot: () => void;
|
|
136
|
+
/** Only after an interactive sign-in; a token refresh must never call it. */
|
|
137
|
+
signedIn: (getProof: () => Promise<string>) => Promise<WebSessionResult>;
|
|
138
|
+
signOut: () => Promise<WebSessionCommandResult>;
|
|
139
|
+
/**
|
|
140
|
+
* Reads the session now, as a heartbeat would, and resolves once the answer
|
|
141
|
+
* and any restore it starts have settled. Reads nothing unless signed in as
|
|
142
|
+
* `expectedUserId` (any user when omitted).
|
|
143
|
+
*/
|
|
144
|
+
refresh: (expectedUserId?: string) => Promise<WebSessionIdentityState>;
|
|
145
|
+
/** Changes with the account; an answer started under an older epoch is stale. */
|
|
146
|
+
getEpoch: () => number;
|
|
147
|
+
/** Cancels timers, ignores answers in flight, and returns to idle. */
|
|
148
|
+
dispose: () => void;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Every tab of a site reads the same host-only cookie, so a sibling's answer
|
|
152
|
+
* is this tab's own session observed elsewhere; that is what makes adopting
|
|
153
|
+
* it safe. A per-tab session scope would break this assumption.
|
|
154
|
+
*/
|
|
155
|
+
declare const zSharedMessage: z.ZodObject<{
|
|
156
|
+
from: z.ZodEnum<["heartbeat", "sign_in", "sign_out"]>;
|
|
157
|
+
result: z.ZodDiscriminatedUnion<"status", [z.ZodObject<{
|
|
158
|
+
status: z.ZodLiteral<"ok">;
|
|
159
|
+
session: z.ZodObject<{
|
|
160
|
+
user: z.ZodObject<{
|
|
161
|
+
id: z.ZodString;
|
|
162
|
+
email: z.ZodString;
|
|
163
|
+
name: z.ZodOptional<z.ZodString>;
|
|
164
|
+
emailVerified: z.ZodBoolean;
|
|
165
|
+
signInProvider: z.ZodOptional<z.ZodString>;
|
|
166
|
+
}, "strip", z.ZodTypeAny, {
|
|
167
|
+
email: string;
|
|
168
|
+
id: string;
|
|
169
|
+
emailVerified: boolean;
|
|
170
|
+
name?: string | undefined;
|
|
171
|
+
signInProvider?: string | undefined;
|
|
172
|
+
}, {
|
|
173
|
+
email: string;
|
|
174
|
+
id: string;
|
|
175
|
+
emailVerified: boolean;
|
|
176
|
+
name?: string | undefined;
|
|
177
|
+
signInProvider?: string | undefined;
|
|
178
|
+
}>;
|
|
179
|
+
csrfToken: z.ZodString;
|
|
180
|
+
expiresAt: z.ZodNumber;
|
|
181
|
+
absoluteExpiresAt: z.ZodNumber;
|
|
182
|
+
}, "strip", z.ZodTypeAny, {
|
|
183
|
+
user: {
|
|
184
|
+
email: string;
|
|
185
|
+
id: string;
|
|
186
|
+
emailVerified: boolean;
|
|
187
|
+
name?: string | undefined;
|
|
188
|
+
signInProvider?: string | undefined;
|
|
189
|
+
};
|
|
190
|
+
expiresAt: number;
|
|
191
|
+
csrfToken: string;
|
|
192
|
+
absoluteExpiresAt: number;
|
|
193
|
+
}, {
|
|
194
|
+
user: {
|
|
195
|
+
email: string;
|
|
196
|
+
id: string;
|
|
197
|
+
emailVerified: boolean;
|
|
198
|
+
name?: string | undefined;
|
|
199
|
+
signInProvider?: string | undefined;
|
|
200
|
+
};
|
|
201
|
+
expiresAt: number;
|
|
202
|
+
csrfToken: string;
|
|
203
|
+
absoluteExpiresAt: number;
|
|
204
|
+
}>;
|
|
205
|
+
}, "strip", z.ZodTypeAny, {
|
|
206
|
+
status: "ok";
|
|
207
|
+
session: {
|
|
208
|
+
user: {
|
|
209
|
+
email: string;
|
|
210
|
+
id: string;
|
|
211
|
+
emailVerified: boolean;
|
|
212
|
+
name?: string | undefined;
|
|
213
|
+
signInProvider?: string | undefined;
|
|
214
|
+
};
|
|
215
|
+
expiresAt: number;
|
|
216
|
+
csrfToken: string;
|
|
217
|
+
absoluteExpiresAt: number;
|
|
218
|
+
};
|
|
219
|
+
}, {
|
|
220
|
+
status: "ok";
|
|
221
|
+
session: {
|
|
222
|
+
user: {
|
|
223
|
+
email: string;
|
|
224
|
+
id: string;
|
|
225
|
+
emailVerified: boolean;
|
|
226
|
+
name?: string | undefined;
|
|
227
|
+
signInProvider?: string | undefined;
|
|
228
|
+
};
|
|
229
|
+
expiresAt: number;
|
|
230
|
+
csrfToken: string;
|
|
231
|
+
absoluteExpiresAt: number;
|
|
232
|
+
};
|
|
233
|
+
}>, z.ZodObject<{
|
|
234
|
+
status: z.ZodLiteral<"error">;
|
|
235
|
+
code: z.ZodLiteral<"SESSION_REVOKED">;
|
|
236
|
+
retryable: z.ZodLiteral<false>;
|
|
237
|
+
}, "strip", z.ZodTypeAny, {
|
|
238
|
+
code: "SESSION_REVOKED";
|
|
239
|
+
status: "error";
|
|
240
|
+
retryable: false;
|
|
241
|
+
}, {
|
|
242
|
+
code: "SESSION_REVOKED";
|
|
243
|
+
status: "error";
|
|
244
|
+
retryable: false;
|
|
245
|
+
}>]>;
|
|
246
|
+
}, "strip", z.ZodTypeAny, {
|
|
247
|
+
result: {
|
|
248
|
+
status: "ok";
|
|
249
|
+
session: {
|
|
250
|
+
user: {
|
|
251
|
+
email: string;
|
|
252
|
+
id: string;
|
|
253
|
+
emailVerified: boolean;
|
|
254
|
+
name?: string | undefined;
|
|
255
|
+
signInProvider?: string | undefined;
|
|
256
|
+
};
|
|
257
|
+
expiresAt: number;
|
|
258
|
+
csrfToken: string;
|
|
259
|
+
absoluteExpiresAt: number;
|
|
260
|
+
};
|
|
261
|
+
} | {
|
|
262
|
+
code: "SESSION_REVOKED";
|
|
263
|
+
status: "error";
|
|
264
|
+
retryable: false;
|
|
265
|
+
};
|
|
266
|
+
from: "heartbeat" | "sign_in" | "sign_out";
|
|
267
|
+
}, {
|
|
268
|
+
result: {
|
|
269
|
+
status: "ok";
|
|
270
|
+
session: {
|
|
271
|
+
user: {
|
|
272
|
+
email: string;
|
|
273
|
+
id: string;
|
|
274
|
+
emailVerified: boolean;
|
|
275
|
+
name?: string | undefined;
|
|
276
|
+
signInProvider?: string | undefined;
|
|
277
|
+
};
|
|
278
|
+
expiresAt: number;
|
|
279
|
+
csrfToken: string;
|
|
280
|
+
absoluteExpiresAt: number;
|
|
281
|
+
};
|
|
282
|
+
} | {
|
|
283
|
+
code: "SESSION_REVOKED";
|
|
284
|
+
status: "error";
|
|
285
|
+
retryable: false;
|
|
286
|
+
};
|
|
287
|
+
from: "heartbeat" | "sign_in" | "sign_out";
|
|
288
|
+
}>;
|
|
289
|
+
type SharedFrom = z.infer<typeof zSharedMessage>['from'];
|
|
290
|
+
/** What one tab of a site tells its siblings, and why. */
|
|
291
|
+
export interface WebSessionSharedMessage {
|
|
292
|
+
readonly from: SharedFrom;
|
|
293
|
+
readonly result: WebSessionResult;
|
|
294
|
+
}
|
|
295
|
+
/** Inert until `boot()`: constructing it sends no request and arms no timer. */
|
|
296
|
+
export declare function createWebSessionIdentity(options: WebSessionIdentityOptions): WebSessionIdentity;
|
|
297
|
+
export {};
|