@trypattern/sdk 0.1.4 → 0.1.6
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/cli/app.js +33 -13
- package/dist/cli/publishing.d.ts +2 -2
- package/dist/cli/publishing.js +30 -9
- package/dist/publishWire.d.ts +36 -0
- package/dist/publishWire.js +25 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/session.d.ts +4 -1
- package/dist/server/session.js +3 -2
- package/package.json +1 -1
package/dist/cli/app.js
CHANGED
|
@@ -13,6 +13,7 @@ import { homedir } from 'node:os';
|
|
|
13
13
|
import { delimiter, dirname, extname, join, relative, resolve } from 'node:path';
|
|
14
14
|
import { pathToFileURL } from 'node:url';
|
|
15
15
|
import { createHash } from 'node:crypto';
|
|
16
|
+
import { z } from 'zod';
|
|
16
17
|
import { resetLocalDatabase } from "../vite/localWorker.js";
|
|
17
18
|
import { login, publish, pull, restore, versions as listVersions } from "./publishing.js";
|
|
18
19
|
import { toolBin } from "./tools.js";
|
|
@@ -73,7 +74,13 @@ const CONTACT_SHEET = join(SCREENSHOTS_DIR, 'contact-sheet.png');
|
|
|
73
74
|
const SCREENSHOT_WORKER = join(SDK_SOURCE, 'cli', `screenshot${SDK_EXTENSION}`);
|
|
74
75
|
const VISUAL_URL_ENV = 'PATTERN_VISUAL_URL';
|
|
75
76
|
const GLOBAL_FLAGS = ['--json', '--help', '-h'];
|
|
76
|
-
const VALUE_FLAGS = new Set([
|
|
77
|
+
const VALUE_FLAGS = new Set([
|
|
78
|
+
'--commands',
|
|
79
|
+
'--name',
|
|
80
|
+
'--as',
|
|
81
|
+
'--code',
|
|
82
|
+
'--message'
|
|
83
|
+
]);
|
|
77
84
|
const SHIM_SOURCE = `#!/bin/sh
|
|
78
85
|
${SHIM_MARKER_LINE}
|
|
79
86
|
dir=$PWD
|
|
@@ -266,8 +273,13 @@ and restore sign in the same way when they need to, so this is rarely run on its
|
|
|
266
273
|
details: `app pull sundayparty
|
|
267
274
|
Downloads the source of the site's latest live version into this folder when it is empty, or into
|
|
268
275
|
./<name> otherwise, writes pattern.json, installs, and runs app setup. Never needs git; when the
|
|
269
|
-
Command Line Tools are installed it also makes a first commit. Signs in first if needed (see app login)
|
|
270
|
-
|
|
276
|
+
Command Line Tools are installed it also makes a first commit. Signs in first if needed (see app login).
|
|
277
|
+
--code <setup code> signs in with the one-time setup code from onpattern.app instead of the browser.`,
|
|
278
|
+
run: (argument, options) => {
|
|
279
|
+
const code = options.get('--code');
|
|
280
|
+
return pull(publishingIo(), argument, process.cwd(), typeof code === 'string' ? code : undefined);
|
|
281
|
+
},
|
|
282
|
+
flags: ['--code'],
|
|
271
283
|
takesArgument: true,
|
|
272
284
|
runsAnywhere: true
|
|
273
285
|
},
|
|
@@ -278,9 +290,14 @@ git would keep, never .dev.vars, .env, node_modules, dist or .dev) to onpattern.
|
|
|
278
290
|
until the new version answers at https://<name>.onpattern.app, printing each step. The database
|
|
279
291
|
moves forward with any new migrations; nothing is ever deleted from it. If a step fails, the site
|
|
280
292
|
keeps running the previous version and the error says why. Run app check first.
|
|
293
|
+
--message '…' says what changed in a few plain words for the owner ("Pink brand colour and a welcome
|
|
294
|
+
line"); onpattern.app and app versions show it beside the version.
|
|
281
295
|
--starter (Pattern's admins only) publishes this project as the starter every new site begins from.`,
|
|
282
|
-
run: (_argument, options) =>
|
|
283
|
-
|
|
296
|
+
run: (_argument, options) => {
|
|
297
|
+
const message = options.get('--message');
|
|
298
|
+
return publish(publishingIo(), ROOT, options.has('--starter'), typeof message === 'string' ? message : undefined);
|
|
299
|
+
},
|
|
300
|
+
flags: ['--starter', '--message']
|
|
284
301
|
},
|
|
285
302
|
versions: {
|
|
286
303
|
summary: 'List the versions that went live, newest first',
|
|
@@ -297,7 +314,7 @@ every row and column added since, which version 3's code ignores.`,
|
|
|
297
314
|
},
|
|
298
315
|
setup: {
|
|
299
316
|
summary: 'Verify Node/pnpm major versions, pnpm install, install the global `app` shim',
|
|
300
|
-
details: `Idempotent. Fails unless Node and pnpm have the major versions in .nvmrc and package.json
|
|
317
|
+
details: `Idempotent. Fails unless Node and pnpm have the major versions in .nvmrc and package.json devEngines.
|
|
301
318
|
Then runs \`pnpm install\` and installs ${SHIM_PATH}, a tiny shim that walks up from the
|
|
302
319
|
current directory to the nearest project launcher (an executable ./app containing the line
|
|
303
320
|
${LAUNCHER_MARKER_LINE}) and runs it, so each project's CLI lives in its repo and the shim
|
|
@@ -1217,13 +1234,16 @@ async function build() {
|
|
|
1217
1234
|
function majorOf(version) {
|
|
1218
1235
|
return version.split('.')[0] ?? '';
|
|
1219
1236
|
}
|
|
1237
|
+
const packagePins = z.object({
|
|
1238
|
+
devEngines: z.object({
|
|
1239
|
+
packageManager: z.object({ version: z.string() })
|
|
1240
|
+
})
|
|
1241
|
+
});
|
|
1220
1242
|
function readPins() {
|
|
1221
1243
|
const node = readText(join(ROOT, '.nvmrc')).trim().replace(/^v/, '');
|
|
1222
|
-
const pkg = JSON.parse(readText(join(ROOT, 'package.json')));
|
|
1223
|
-
const
|
|
1224
|
-
|
|
1225
|
-
: '';
|
|
1226
|
-
return { node, pnpm: pm.replace(/^pnpm@/, '').split('+')[0] ?? '' };
|
|
1244
|
+
const pkg = packagePins.safeParse(JSON.parse(readText(join(ROOT, 'package.json'))));
|
|
1245
|
+
const pnpm = pkg.success ? pkg.data.devEngines.packageManager.version : '';
|
|
1246
|
+
return { node, pnpm: pnpm.replace(/^>=/, '') };
|
|
1227
1247
|
}
|
|
1228
1248
|
function isPatternShim(source) {
|
|
1229
1249
|
const lines = source.split('\n');
|
|
@@ -1260,7 +1280,7 @@ async function setup() {
|
|
|
1260
1280
|
problems.push(`Node ${haveNode} is not Node ${majorOf(pins.node)} (.nvmrc says ${pins.node})\n fix pnpm env use --global ${majorOf(pins.node)}`);
|
|
1261
1281
|
}
|
|
1262
1282
|
if (majorOf(havePnpm) !== majorOf(pins.pnpm)) {
|
|
1263
|
-
problems.push(`pnpm ${havePnpm || '(not found)'} is not pnpm ${majorOf(pins.pnpm)} (package.json
|
|
1283
|
+
problems.push(`pnpm ${havePnpm || '(not found)'} is not pnpm ${majorOf(pins.pnpm)} (package.json devEngines says ${pins.pnpm} or newer)\n fix curl -fsSL https://get.pnpm.io/install.sh | sh -`);
|
|
1264
1284
|
}
|
|
1265
1285
|
const versions = { node: haveNode, pnpm: havePnpm, expected: pins };
|
|
1266
1286
|
if (problems.length > 0) {
|
|
@@ -1302,7 +1322,7 @@ async function setup() {
|
|
|
1302
1322
|
function help() {
|
|
1303
1323
|
const width = Math.max(...Object.keys(COMMANDS).map((n) => n.length));
|
|
1304
1324
|
const lines = Object.entries(COMMANDS).map(([name, cmd]) => `app ${name.padEnd(width)} ${cmd.summary}`);
|
|
1305
|
-
lines.push('Flags: --json (machine-readable stdout), <command> --help (details and its own flags: start --no-open, test --visual, screenshot --commands --name --as --signed-out)');
|
|
1325
|
+
lines.push('Flags: --json (machine-readable stdout), <command> --help (details and its own flags: start --no-open, test --visual, screenshot --commands --name --as --signed-out, pull --code, publish --message)');
|
|
1306
1326
|
return {
|
|
1307
1327
|
code: 0,
|
|
1308
1328
|
data: {
|
package/dist/cli/publishing.d.ts
CHANGED
|
@@ -14,8 +14,8 @@ export type PublishingIo = {
|
|
|
14
14
|
sdkVersion: string;
|
|
15
15
|
};
|
|
16
16
|
export declare function login(io: PublishingIo): Promise<Outcome>;
|
|
17
|
-
export declare function pull(io: PublishingIo, name: string | undefined, cwd: string): Promise<Outcome>;
|
|
18
|
-
export declare function publish(io: PublishingIo, root: string, isStarter: boolean): Promise<Outcome>;
|
|
17
|
+
export declare function pull(io: PublishingIo, name: string | undefined, cwd: string, setupCode: string | undefined): Promise<Outcome>;
|
|
18
|
+
export declare function publish(io: PublishingIo, root: string, isStarter: boolean, message: string | undefined): Promise<Outcome>;
|
|
19
19
|
export declare function versions(io: PublishingIo, root: string): Promise<Outcome>;
|
|
20
20
|
export declare function restore(io: PublishingIo, root: string, number: string | undefined): Promise<Outcome>;
|
|
21
21
|
export {};
|
package/dist/cli/publishing.js
CHANGED
|
@@ -3,7 +3,7 @@ import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, st
|
|
|
3
3
|
import { homedir, hostname, userInfo } from 'node:os';
|
|
4
4
|
import { basename, dirname, extname, join, matchesGlob, relative } from 'node:path';
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
-
import { DASHBOARD_URL, UPLOAD, appSummary, isPrivatePath, loginPoll, loginStarted, nameProblem, publishSummary, sourcePathProblem } from "../publishWire.js";
|
|
6
|
+
import { DASHBOARD_URL, UPLOAD, appSummary, isPrivatePath, loginPoll, loginStarted, nameProblem, publishMessage, publishSummary, setupCodeExchanged, sourcePathProblem } from "../publishWire.js";
|
|
7
7
|
import { appInfo } from "../appTitle.js";
|
|
8
8
|
import { PROJECT_FILE, readProjectFile } from "../vite/projectFile.js";
|
|
9
9
|
const CONFIG_DIR = join(homedir(), '.config', 'pattern');
|
|
@@ -175,6 +175,20 @@ async function signIn(io, again) {
|
|
|
175
175
|
text: `Opened ${started.url} in the browser.\n code ${started.code}\n next tell them: "Check the code on the page is ${started.code}, then click Allow." Then, without waiting for them to reply, run ${again} again: it waits for Allow.`
|
|
176
176
|
};
|
|
177
177
|
}
|
|
178
|
+
async function useSetupCode(io, code) {
|
|
179
|
+
const response = await fetch(`${dashboard()}/api/auth/cli/setup-codes/exchange`, {
|
|
180
|
+
method: 'POST',
|
|
181
|
+
headers: { 'content-type': 'application/json' },
|
|
182
|
+
body: JSON.stringify({ code, label: labelOfThisMachine() })
|
|
183
|
+
}).catch(() => undefined);
|
|
184
|
+
const exchanged = setupCodeExchanged.safeParse(await response?.json().catch(() => null));
|
|
185
|
+
if (response?.ok === true && exchanged.success) {
|
|
186
|
+
saveCookie(exchanged.data.cookie);
|
|
187
|
+
io.say('✓ Connected with the setup code');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
io.say('✗ That setup code has expired or was already used');
|
|
191
|
+
}
|
|
178
192
|
async function signedIn(io, again, work) {
|
|
179
193
|
if (savedCookie() === undefined) {
|
|
180
194
|
const outcome = await signIn(io, again);
|
|
@@ -237,7 +251,7 @@ function folderFor(name, cwd) {
|
|
|
237
251
|
function commandLineToolsReady() {
|
|
238
252
|
return spawnSync('xcode-select', ['-p'], { stdio: 'ignore' }).status === 0;
|
|
239
253
|
}
|
|
240
|
-
export async function pull(io, name, cwd) {
|
|
254
|
+
export async function pull(io, name, cwd, setupCode) {
|
|
241
255
|
if (name === undefined || nameProblem(name) !== undefined) {
|
|
242
256
|
return {
|
|
243
257
|
code: 2,
|
|
@@ -254,6 +268,8 @@ export async function pull(io, name, cwd) {
|
|
|
254
268
|
};
|
|
255
269
|
}
|
|
256
270
|
try {
|
|
271
|
+
if (setupCode !== undefined)
|
|
272
|
+
await useSetupCode(io, setupCode);
|
|
257
273
|
const result = await signedIn(io, `app pull ${name}`, async () => {
|
|
258
274
|
const app = await callJson(`/api/apps/${name}`, appSummary);
|
|
259
275
|
const response = await call(`/api/apps/${name}/source`);
|
|
@@ -408,11 +424,13 @@ async function followPublish(io, name, started) {
|
|
|
408
424
|
}
|
|
409
425
|
const data = { name, version: publish.number, status: publish.status };
|
|
410
426
|
if (publish.status === 'live') {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
427
|
+
const lines = [
|
|
428
|
+
`✓ Version ${publish.number} is live at https://${name}.onpattern.app${publish.message === null ? '' : ` · ${publish.message}`}`
|
|
429
|
+
];
|
|
430
|
+
if (publish.message === null && publish.restoredFrom === null) {
|
|
431
|
+
lines.push(" tip add --message '…' so the owner sees what changed, in plain words");
|
|
432
|
+
}
|
|
433
|
+
return { code: 0, data, text: lines.join('\n') };
|
|
416
434
|
}
|
|
417
435
|
if (publish.status === 'failed') {
|
|
418
436
|
return {
|
|
@@ -427,7 +445,7 @@ async function followPublish(io, name, started) {
|
|
|
427
445
|
text: `✗ Version ${publish.number} is still publishing after ${PUBLISH_WAIT_MS / 60_000} minutes\n next app versions shows how it ends`
|
|
428
446
|
};
|
|
429
447
|
}
|
|
430
|
-
export async function publish(io, root, isStarter) {
|
|
448
|
+
export async function publish(io, root, isStarter, message) {
|
|
431
449
|
try {
|
|
432
450
|
const { name } = readProjectFile(root);
|
|
433
451
|
const built = await io.build();
|
|
@@ -435,6 +453,9 @@ export async function publish(io, root, isStarter) {
|
|
|
435
453
|
return built;
|
|
436
454
|
io.say('✓ Built');
|
|
437
455
|
const { form, sources } = uploadForm(root, io, isStarter);
|
|
456
|
+
const said = publishMessage(message ?? '');
|
|
457
|
+
if (said !== null)
|
|
458
|
+
form.append(UPLOAD.message, said);
|
|
438
459
|
io.say(`✓ Packed the build and ${sources} source files`);
|
|
439
460
|
const again = isStarter ? 'app publish --starter' : 'app publish';
|
|
440
461
|
const result = await signedIn(io, again, async () => {
|
|
@@ -476,7 +497,7 @@ export async function versions(io, root) {
|
|
|
476
497
|
? `restored version ${item.restoredFrom}`
|
|
477
498
|
: item.isStarter
|
|
478
499
|
? 'starter site'
|
|
479
|
-
: `published by ${item.byEmail}
|
|
500
|
+
: (item.message ?? `published by ${item.byEmail}`);
|
|
480
501
|
return ` ${String(item.number).padStart(3)} ${item.status.padEnd(7)} ${item.startedAt.slice(0, 16).replace('T', ' ')} ${what}`;
|
|
481
502
|
});
|
|
482
503
|
return {
|
package/dist/publishWire.d.ts
CHANGED
|
@@ -17,7 +17,10 @@ export declare const UPLOAD: {
|
|
|
17
17
|
readonly source: "source/";
|
|
18
18
|
readonly compatibilityDate: "compatibilityDate";
|
|
19
19
|
readonly sdkVersion: "sdkVersion";
|
|
20
|
+
readonly message: "message";
|
|
20
21
|
};
|
|
22
|
+
export declare const PUBLISH_MESSAGE_LIMIT = 100;
|
|
23
|
+
export declare function publishMessage(text: string): string | null;
|
|
21
24
|
export declare const publishStep: z.ZodEnum<{
|
|
22
25
|
publish: "publish";
|
|
23
26
|
reserve: "reserve";
|
|
@@ -47,6 +50,7 @@ export declare const publishSummary: z.ZodObject<{
|
|
|
47
50
|
byEmail: z.ZodString;
|
|
48
51
|
restoredFrom: z.ZodNullable<z.ZodNumber>;
|
|
49
52
|
isStarter: z.ZodBoolean;
|
|
53
|
+
message: z.ZodNullable<z.ZodString>;
|
|
50
54
|
startedAt: z.ZodString;
|
|
51
55
|
finishedAt: z.ZodNullable<z.ZodString>;
|
|
52
56
|
}, z.core.$strip>;
|
|
@@ -73,6 +77,7 @@ export declare const appSummary: z.ZodObject<{
|
|
|
73
77
|
byEmail: z.ZodString;
|
|
74
78
|
restoredFrom: z.ZodNullable<z.ZodNumber>;
|
|
75
79
|
isStarter: z.ZodBoolean;
|
|
80
|
+
message: z.ZodNullable<z.ZodString>;
|
|
76
81
|
startedAt: z.ZodString;
|
|
77
82
|
finishedAt: z.ZodNullable<z.ZodString>;
|
|
78
83
|
}, z.core.$strip>>;
|
|
@@ -99,6 +104,18 @@ export declare const loginToApprove: z.ZodObject<{
|
|
|
99
104
|
code: z.ZodString;
|
|
100
105
|
label: z.ZodString;
|
|
101
106
|
}, z.core.$strip>;
|
|
107
|
+
export declare const setupCode: z.ZodObject<{
|
|
108
|
+
code: z.ZodString;
|
|
109
|
+
expiresAt: z.ZodString;
|
|
110
|
+
}, z.core.$strip>;
|
|
111
|
+
export declare const setupCodeExchanged: z.ZodObject<{
|
|
112
|
+
cookie: z.ZodString;
|
|
113
|
+
}, z.core.$strip>;
|
|
114
|
+
export declare const connection: z.ZodObject<{
|
|
115
|
+
label: z.ZodString;
|
|
116
|
+
connectedAt: z.ZodString;
|
|
117
|
+
}, z.core.$strip>;
|
|
118
|
+
export type Connection = z.output<typeof connection>;
|
|
102
119
|
export declare const publishServices: {
|
|
103
120
|
readonly apps: {
|
|
104
121
|
readonly list: NoInfer<import("./services.ts").ServiceCall<"/apps", {}, z.ZodArray<z.ZodObject<{
|
|
@@ -123,6 +140,7 @@ export declare const publishServices: {
|
|
|
123
140
|
byEmail: z.ZodString;
|
|
124
141
|
restoredFrom: z.ZodNullable<z.ZodNumber>;
|
|
125
142
|
isStarter: z.ZodBoolean;
|
|
143
|
+
message: z.ZodNullable<z.ZodString>;
|
|
126
144
|
startedAt: z.ZodString;
|
|
127
145
|
finishedAt: z.ZodNullable<z.ZodString>;
|
|
128
146
|
}, z.core.$strip>>;
|
|
@@ -149,6 +167,7 @@ export declare const publishServices: {
|
|
|
149
167
|
byEmail: z.ZodString;
|
|
150
168
|
restoredFrom: z.ZodNullable<z.ZodNumber>;
|
|
151
169
|
isStarter: z.ZodBoolean;
|
|
170
|
+
message: z.ZodNullable<z.ZodString>;
|
|
152
171
|
startedAt: z.ZodString;
|
|
153
172
|
finishedAt: z.ZodNullable<z.ZodString>;
|
|
154
173
|
}, z.core.$strip>>;
|
|
@@ -178,6 +197,7 @@ export declare const publishServices: {
|
|
|
178
197
|
byEmail: z.ZodString;
|
|
179
198
|
restoredFrom: z.ZodNullable<z.ZodNumber>;
|
|
180
199
|
isStarter: z.ZodBoolean;
|
|
200
|
+
message: z.ZodNullable<z.ZodString>;
|
|
181
201
|
startedAt: z.ZodString;
|
|
182
202
|
finishedAt: z.ZodNullable<z.ZodString>;
|
|
183
203
|
}, z.core.$strip>>;
|
|
@@ -215,6 +235,7 @@ export declare const publishServices: {
|
|
|
215
235
|
byEmail: z.ZodString;
|
|
216
236
|
restoredFrom: z.ZodNullable<z.ZodNumber>;
|
|
217
237
|
isStarter: z.ZodBoolean;
|
|
238
|
+
message: z.ZodNullable<z.ZodString>;
|
|
218
239
|
startedAt: z.ZodString;
|
|
219
240
|
finishedAt: z.ZodNullable<z.ZodString>;
|
|
220
241
|
}, z.core.$strip>>>>;
|
|
@@ -235,6 +256,7 @@ export declare const publishServices: {
|
|
|
235
256
|
byEmail: z.ZodString;
|
|
236
257
|
restoredFrom: z.ZodNullable<z.ZodNumber>;
|
|
237
258
|
isStarter: z.ZodBoolean;
|
|
259
|
+
message: z.ZodNullable<z.ZodString>;
|
|
238
260
|
startedAt: z.ZodString;
|
|
239
261
|
finishedAt: z.ZodNullable<z.ZodString>;
|
|
240
262
|
}, z.core.$strip>>>;
|
|
@@ -255,10 +277,24 @@ export declare const publishServices: {
|
|
|
255
277
|
byEmail: z.ZodString;
|
|
256
278
|
restoredFrom: z.ZodNullable<z.ZodNumber>;
|
|
257
279
|
isStarter: z.ZodBoolean;
|
|
280
|
+
message: z.ZodNullable<z.ZodString>;
|
|
258
281
|
startedAt: z.ZodString;
|
|
259
282
|
finishedAt: z.ZodNullable<z.ZodString>;
|
|
260
283
|
}, z.core.$strip>>>;
|
|
261
284
|
};
|
|
285
|
+
readonly setup: {
|
|
286
|
+
readonly newCode: NoInfer<import("./services.ts").ServiceCall<"/apps/:name/setup-code", {}, z.ZodObject<{
|
|
287
|
+
code: z.ZodString;
|
|
288
|
+
expiresAt: z.ZodString;
|
|
289
|
+
}, z.core.$strip>>>;
|
|
290
|
+
readonly connection: NoInfer<import("./services.ts").ServiceCall<"/apps/:name/connection", {}, z.ZodNullable<z.ZodObject<{
|
|
291
|
+
label: z.ZodString;
|
|
292
|
+
connectedAt: z.ZodString;
|
|
293
|
+
}, z.core.$strip>>>>;
|
|
294
|
+
readonly disconnect: NoInfer<import("./services.ts").ServiceCall<"/apps/:name/connection/disconnect", {}, z.ZodObject<{
|
|
295
|
+
ok: z.ZodBoolean;
|
|
296
|
+
}, z.core.$strip>>>;
|
|
297
|
+
};
|
|
262
298
|
readonly logins: {
|
|
263
299
|
readonly read: NoInfer<import("./services.ts").ServiceCall<"/cli/logins/:approval", {}, z.ZodObject<{
|
|
264
300
|
code: z.ZodString;
|
package/dist/publishWire.js
CHANGED
|
@@ -89,8 +89,14 @@ export const UPLOAD = {
|
|
|
89
89
|
migrations: 'migrations/',
|
|
90
90
|
source: 'source/',
|
|
91
91
|
compatibilityDate: 'compatibilityDate',
|
|
92
|
-
sdkVersion: 'sdkVersion'
|
|
92
|
+
sdkVersion: 'sdkVersion',
|
|
93
|
+
message: 'message'
|
|
93
94
|
};
|
|
95
|
+
export const PUBLISH_MESSAGE_LIMIT = 100;
|
|
96
|
+
export function publishMessage(text) {
|
|
97
|
+
const firstLine = (text.split('\n')[0] ?? '').replaceAll(/\s+/g, ' ').trim();
|
|
98
|
+
return firstLine === '' ? null : firstLine.slice(0, PUBLISH_MESSAGE_LIMIT);
|
|
99
|
+
}
|
|
94
100
|
export const publishStep = z.enum(['reserve', 'database', 'sign-in', 'publish']);
|
|
95
101
|
export const publishStatus = z.enum(['running', 'live', 'failed']);
|
|
96
102
|
export const publishSummary = z.object({
|
|
@@ -101,6 +107,7 @@ export const publishSummary = z.object({
|
|
|
101
107
|
byEmail: z.string(),
|
|
102
108
|
restoredFrom: z.number().nullable(),
|
|
103
109
|
isStarter: z.boolean(),
|
|
110
|
+
message: z.string().nullable(),
|
|
104
111
|
startedAt: z.string(),
|
|
105
112
|
finishedAt: z.string().nullable()
|
|
106
113
|
});
|
|
@@ -126,6 +133,12 @@ export const loginPoll = z.union([
|
|
|
126
133
|
z.object({ status: z.literal('approved'), cookie: z.string() })
|
|
127
134
|
]);
|
|
128
135
|
export const loginToApprove = z.object({ code: z.string(), label: z.string() });
|
|
136
|
+
export const setupCode = z.object({ code: z.string(), expiresAt: z.string() });
|
|
137
|
+
export const setupCodeExchanged = z.object({ cookie: z.string() });
|
|
138
|
+
export const connection = z.object({
|
|
139
|
+
label: z.string(),
|
|
140
|
+
connectedAt: z.string()
|
|
141
|
+
});
|
|
129
142
|
export const publishServices = defineServices({
|
|
130
143
|
apps: {
|
|
131
144
|
list: call({ get: '/apps', reply: z.array(appSummary) }),
|
|
@@ -158,6 +171,17 @@ export const publishServices = defineServices({
|
|
|
158
171
|
reply: publishSummary
|
|
159
172
|
})
|
|
160
173
|
},
|
|
174
|
+
setup: {
|
|
175
|
+
newCode: call({ post: '/apps/:name/setup-code', reply: setupCode }),
|
|
176
|
+
connection: call({
|
|
177
|
+
get: '/apps/:name/connection',
|
|
178
|
+
reply: connection.nullable()
|
|
179
|
+
}),
|
|
180
|
+
disconnect: call({
|
|
181
|
+
post: '/apps/:name/connection/disconnect',
|
|
182
|
+
reply: z.object({ ok: z.boolean() })
|
|
183
|
+
})
|
|
184
|
+
},
|
|
161
185
|
logins: {
|
|
162
186
|
read: call({ get: '/cli/logins/:approval', reply: loginToApprove }),
|
|
163
187
|
approve: call({
|
package/dist/server/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { refused } from '../services.ts';
|
|
|
5
5
|
export { serveServices } from './services.ts';
|
|
6
6
|
export type { ServiceHandlers } from './services.ts';
|
|
7
7
|
export { sessionCookieFor } from './session.ts';
|
|
8
|
-
export { sessions } from './sessions.ts';
|
|
8
|
+
export { deleteSession, sessions } from './sessions.ts';
|
|
9
9
|
export { readTitle, seedTitleSql, settings, writeTitle } from './settings.ts';
|
|
10
10
|
export { exchangeReply, exchangeRequest, sendCodeReply, sendCodeRequest, verifiedIdentity, verifyCodeReply, verifyCodeRequest } from './signInWire.ts';
|
|
11
11
|
export type { VerifiedIdentity } from './signInWire.ts';
|
package/dist/server/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export { seedSql, serveTables, sqlTable, sqlTables } from "./tables.js";
|
|
|
3
3
|
export { refused } from "../services.js";
|
|
4
4
|
export { serveServices } from "./services.js";
|
|
5
5
|
export { sessionCookieFor } from "./session.js";
|
|
6
|
-
export { sessions } from "./sessions.js";
|
|
6
|
+
export { deleteSession, sessions } from "./sessions.js";
|
|
7
7
|
export { readTitle, seedTitleSql, settings, writeTitle } from "./settings.js";
|
|
8
8
|
export { exchangeReply, exchangeRequest, sendCodeReply, sendCodeRequest, verifiedIdentity, verifyCodeReply, verifyCodeRequest } from "./signInWire.js";
|
|
9
9
|
export { findUser, users } from "./users.js";
|
package/dist/server/session.d.ts
CHANGED
|
@@ -17,7 +17,10 @@ export declare function issuePass(c: Context<ServerEnv>, user: StoredUser, sessi
|
|
|
17
17
|
recheckAt: number;
|
|
18
18
|
}>;
|
|
19
19
|
export declare function startSession(c: Context<ServerEnv>, user: StoredUser): Promise<void>;
|
|
20
|
-
export declare function sessionCookieFor(env: ServerEnv['Bindings'], user: StoredUser): Promise<
|
|
20
|
+
export declare function sessionCookieFor(env: ServerEnv['Bindings'], user: StoredUser): Promise<{
|
|
21
|
+
cookie: string;
|
|
22
|
+
sessionId: `${string}-${string}-${string}-${string}-${string}`;
|
|
23
|
+
}>;
|
|
21
24
|
export declare function readPass(c: Context<ServerEnv>): Promise<{
|
|
22
25
|
sessionId: string;
|
|
23
26
|
userId: string;
|
package/dist/server/session.js
CHANGED
|
@@ -37,14 +37,15 @@ export async function startSession(c, user) {
|
|
|
37
37
|
await issuePass(c, user, await createSession(c.env.DB, user.id));
|
|
38
38
|
}
|
|
39
39
|
export async function sessionCookieFor(env, user) {
|
|
40
|
+
const sessionId = await createSession(env.DB, user.id);
|
|
40
41
|
const pass = {
|
|
41
|
-
sessionId
|
|
42
|
+
sessionId,
|
|
42
43
|
userId: user.id,
|
|
43
44
|
email: user.email,
|
|
44
45
|
recheckAt: nowInSeconds() + RECHECK_SECONDS
|
|
45
46
|
};
|
|
46
47
|
const cookie = await serializeSigned(SESSION_COOKIE, JSON.stringify(pass), env.SESSION_SECRET);
|
|
47
|
-
return cookie.split(';')[0] ?? cookie;
|
|
48
|
+
return { cookie: cookie.split(';')[0] ?? cookie, sessionId };
|
|
48
49
|
}
|
|
49
50
|
export async function readPass(c) {
|
|
50
51
|
const value = await getSignedCookie(c, c.env.SESSION_SECRET, SESSION_COOKIE);
|