@trypattern/sdk 0.1.3 → 0.1.5
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/builtins/Account.js +1 -1
- package/dist/cli/app.js +20 -11
- package/dist/cli/publishing.d.ts +1 -1
- package/dist/cli/publishing.js +21 -5
- package/dist/components/Appear.d.ts +6 -0
- package/dist/components/Appear.js +21 -0
- package/dist/components/Badge.d.ts +1 -1
- package/dist/components/Badge.js +18 -0
- package/dist/components/Link.d.ts +1 -1
- package/dist/components/Link.js +6 -0
- package/dist/components/SignInScreen.js +1 -1
- package/dist/components/TextField.js +10 -1
- package/dist/publishWire.d.ts +25 -0
- package/dist/publishWire.js +17 -0
- package/dist/react.d.ts +1 -0
- package/dist/react.js +1 -0
- package/dist/rules/lintPlugin.js +1 -0
- 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/builtins/Account.js
CHANGED
|
@@ -2,7 +2,7 @@ import { appearance } from "../appearance.js";
|
|
|
2
2
|
import { command } from "../model.js";
|
|
3
3
|
import { Model } from "../registered.js";
|
|
4
4
|
export class Account extends Model({
|
|
5
|
-
state: { appearance: appearance.default('
|
|
5
|
+
state: { appearance: appearance.default('light') },
|
|
6
6
|
persist: ['appearance']
|
|
7
7
|
}) {
|
|
8
8
|
get user() {
|
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,7 @@ 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(['--commands', '--name', '--as']);
|
|
77
|
+
const VALUE_FLAGS = new Set(['--commands', '--name', '--as', '--code']);
|
|
77
78
|
const SHIM_SOURCE = `#!/bin/sh
|
|
78
79
|
${SHIM_MARKER_LINE}
|
|
79
80
|
dir=$PWD
|
|
@@ -266,8 +267,13 @@ and restore sign in the same way when they need to, so this is rarely run on its
|
|
|
266
267
|
details: `app pull sundayparty
|
|
267
268
|
Downloads the source of the site's latest live version into this folder when it is empty, or into
|
|
268
269
|
./<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
|
-
|
|
270
|
+
Command Line Tools are installed it also makes a first commit. Signs in first if needed (see app login).
|
|
271
|
+
--code <setup code> signs in with the one-time setup code from onpattern.app instead of the browser.`,
|
|
272
|
+
run: (argument, options) => {
|
|
273
|
+
const code = options.get('--code');
|
|
274
|
+
return pull(publishingIo(), argument, process.cwd(), typeof code === 'string' ? code : undefined);
|
|
275
|
+
},
|
|
276
|
+
flags: ['--code'],
|
|
271
277
|
takesArgument: true,
|
|
272
278
|
runsAnywhere: true
|
|
273
279
|
},
|
|
@@ -297,7 +303,7 @@ every row and column added since, which version 3's code ignores.`,
|
|
|
297
303
|
},
|
|
298
304
|
setup: {
|
|
299
305
|
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
|
|
306
|
+
details: `Idempotent. Fails unless Node and pnpm have the major versions in .nvmrc and package.json devEngines.
|
|
301
307
|
Then runs \`pnpm install\` and installs ${SHIM_PATH}, a tiny shim that walks up from the
|
|
302
308
|
current directory to the nearest project launcher (an executable ./app containing the line
|
|
303
309
|
${LAUNCHER_MARKER_LINE}) and runs it, so each project's CLI lives in its repo and the shim
|
|
@@ -1217,13 +1223,16 @@ async function build() {
|
|
|
1217
1223
|
function majorOf(version) {
|
|
1218
1224
|
return version.split('.')[0] ?? '';
|
|
1219
1225
|
}
|
|
1226
|
+
const packagePins = z.object({
|
|
1227
|
+
devEngines: z.object({
|
|
1228
|
+
packageManager: z.object({ version: z.string() })
|
|
1229
|
+
})
|
|
1230
|
+
});
|
|
1220
1231
|
function readPins() {
|
|
1221
1232
|
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] ?? '' };
|
|
1233
|
+
const pkg = packagePins.safeParse(JSON.parse(readText(join(ROOT, 'package.json'))));
|
|
1234
|
+
const pnpm = pkg.success ? pkg.data.devEngines.packageManager.version : '';
|
|
1235
|
+
return { node, pnpm: pnpm.replace(/^>=/, '') };
|
|
1227
1236
|
}
|
|
1228
1237
|
function isPatternShim(source) {
|
|
1229
1238
|
const lines = source.split('\n');
|
|
@@ -1260,7 +1269,7 @@ async function setup() {
|
|
|
1260
1269
|
problems.push(`Node ${haveNode} is not Node ${majorOf(pins.node)} (.nvmrc says ${pins.node})\n fix pnpm env use --global ${majorOf(pins.node)}`);
|
|
1261
1270
|
}
|
|
1262
1271
|
if (majorOf(havePnpm) !== majorOf(pins.pnpm)) {
|
|
1263
|
-
problems.push(`pnpm ${havePnpm || '(not found)'} is not pnpm ${majorOf(pins.pnpm)} (package.json
|
|
1272
|
+
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
1273
|
}
|
|
1265
1274
|
const versions = { node: haveNode, pnpm: havePnpm, expected: pins };
|
|
1266
1275
|
if (problems.length > 0) {
|
|
@@ -1302,7 +1311,7 @@ async function setup() {
|
|
|
1302
1311
|
function help() {
|
|
1303
1312
|
const width = Math.max(...Object.keys(COMMANDS).map((n) => n.length));
|
|
1304
1313
|
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)');
|
|
1314
|
+
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)');
|
|
1306
1315
|
return {
|
|
1307
1316
|
code: 0,
|
|
1308
1317
|
data: {
|
package/dist/cli/publishing.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ 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>;
|
|
17
|
+
export declare function pull(io: PublishingIo, name: string | undefined, cwd: string, setupCode: string | undefined): Promise<Outcome>;
|
|
18
18
|
export declare function publish(io: PublishingIo, root: string, isStarter: boolean): 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>;
|
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, 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');
|
|
@@ -11,7 +11,7 @@ const CREDENTIALS_FILE = join(CONFIG_DIR, 'credentials.json');
|
|
|
11
11
|
const PENDING_FILE = join(CONFIG_DIR, 'pending-login.json');
|
|
12
12
|
const LOGIN_MINUTES = 10;
|
|
13
13
|
const POLL_MS = 2000;
|
|
14
|
-
const LOGIN_WAIT_MS =
|
|
14
|
+
const LOGIN_WAIT_MS = 100_000;
|
|
15
15
|
const PUBLISH_WAIT_MS = 300_000;
|
|
16
16
|
const SESSION_COOKIE = 'pattern_session';
|
|
17
17
|
const LAUNCHER = 'app';
|
|
@@ -154,7 +154,7 @@ async function signIn(io, again) {
|
|
|
154
154
|
return {
|
|
155
155
|
code: 3,
|
|
156
156
|
data: { waitingFor: 'approval', code: pending.code, url: pending.url },
|
|
157
|
-
text: `✗ Not allowed yet. The browser page ${pending.url} shows the code ${pending.code}.\n next
|
|
157
|
+
text: `✗ Not allowed yet. The browser page ${pending.url} shows the code ${pending.code}.\n next run ${again} again: it waits for Allow`
|
|
158
158
|
};
|
|
159
159
|
}
|
|
160
160
|
const response = await fetch(`${dashboard()}/api/auth/cli/logins`, {
|
|
@@ -172,9 +172,23 @@ async function signIn(io, again) {
|
|
|
172
172
|
return {
|
|
173
173
|
code: 3,
|
|
174
174
|
data: { waitingFor: 'approval', code: started.code, url: started.url },
|
|
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 run ${again} again.`
|
|
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`);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as stylex from '@stylexjs/stylex';
|
|
3
|
+
import { breakpoints, motion, space } from "../theme/tokens.stylex.js";
|
|
4
|
+
export function Appear({ children }) {
|
|
5
|
+
return _jsx("div", { ...stylex.props(styles.appear), children: children });
|
|
6
|
+
}
|
|
7
|
+
const enter = stylex.keyframes({
|
|
8
|
+
from: { opacity: 0, transform: `translateY(${space.xs})` }
|
|
9
|
+
});
|
|
10
|
+
const styles = stylex.create({
|
|
11
|
+
appear: {
|
|
12
|
+
display: 'flex',
|
|
13
|
+
flexDirection: 'column',
|
|
14
|
+
animationName: {
|
|
15
|
+
default: enter,
|
|
16
|
+
[breakpoints.reducedMotion]: 'none'
|
|
17
|
+
},
|
|
18
|
+
animationDuration: motion.base,
|
|
19
|
+
animationTimingFunction: motion.easeOut
|
|
20
|
+
}
|
|
21
|
+
});
|
|
@@ -3,7 +3,7 @@ import type { Placement } from './Placement.ts';
|
|
|
3
3
|
type BadgeProps = {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
variant?: 'primary' | 'tertiary' | 'outline' | 'transparent';
|
|
6
|
-
tone?: 'neutral' | 'brand' | 'danger';
|
|
6
|
+
tone?: 'neutral' | 'brand' | 'positive' | 'danger';
|
|
7
7
|
size?: 'sm' | 'md';
|
|
8
8
|
style?: Placement;
|
|
9
9
|
};
|
package/dist/components/Badge.js
CHANGED
|
@@ -7,6 +7,7 @@ export function Badge({ children, variant = 'tertiary', tone = 'neutral', size =
|
|
|
7
7
|
const toneKeys = {
|
|
8
8
|
neutral: 'Neutral',
|
|
9
9
|
brand: 'Brand',
|
|
10
|
+
positive: 'Positive',
|
|
10
11
|
danger: 'Danger'
|
|
11
12
|
};
|
|
12
13
|
const styles = stylex.create({
|
|
@@ -41,6 +42,10 @@ const looks = stylex.create({
|
|
|
41
42
|
color: colors.onBrandSolidForeground,
|
|
42
43
|
backgroundColor: colors.brandSolid
|
|
43
44
|
},
|
|
45
|
+
primaryPositive: {
|
|
46
|
+
color: colors.onPositiveSolidForeground,
|
|
47
|
+
backgroundColor: colors.positiveSolid
|
|
48
|
+
},
|
|
44
49
|
primaryDanger: {
|
|
45
50
|
color: colors.onDangerSolidForeground,
|
|
46
51
|
backgroundColor: colors.dangerSolid
|
|
@@ -53,6 +58,10 @@ const looks = stylex.create({
|
|
|
53
58
|
color: colors.onBrandSubtleForeground,
|
|
54
59
|
backgroundColor: colors.brandSubtle
|
|
55
60
|
},
|
|
61
|
+
tertiaryPositive: {
|
|
62
|
+
color: colors.onPositiveSubtleForeground,
|
|
63
|
+
backgroundColor: colors.positiveSubtle
|
|
64
|
+
},
|
|
56
65
|
tertiaryDanger: {
|
|
57
66
|
color: colors.dangerText,
|
|
58
67
|
backgroundColor: colors.dangerSubtleHover
|
|
@@ -67,6 +76,11 @@ const looks = stylex.create({
|
|
|
67
76
|
backgroundColor: 'transparent',
|
|
68
77
|
boxShadow: `inset 0 0 0 ${borders.thin} ${colors.brandBorderDefault}`
|
|
69
78
|
},
|
|
79
|
+
outlinePositive: {
|
|
80
|
+
color: colors.positiveForeground,
|
|
81
|
+
backgroundColor: 'transparent',
|
|
82
|
+
boxShadow: `inset 0 0 0 ${borders.thin} ${colors.positiveBorderDefault}`
|
|
83
|
+
},
|
|
70
84
|
outlineDanger: {
|
|
71
85
|
color: colors.dangerForeground,
|
|
72
86
|
backgroundColor: 'transparent',
|
|
@@ -80,6 +94,10 @@ const looks = stylex.create({
|
|
|
80
94
|
color: colors.brandForeground,
|
|
81
95
|
backgroundColor: 'transparent'
|
|
82
96
|
},
|
|
97
|
+
transparentPositive: {
|
|
98
|
+
color: colors.positiveForeground,
|
|
99
|
+
backgroundColor: 'transparent'
|
|
100
|
+
},
|
|
83
101
|
transparentDanger: {
|
|
84
102
|
color: colors.dangerForeground,
|
|
85
103
|
backgroundColor: 'transparent'
|
package/dist/components/Link.js
CHANGED
|
@@ -35,6 +35,12 @@ const looks = stylex.create({
|
|
|
35
35
|
':hover': colors.brandSolidHover
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
|
+
positive: {
|
|
39
|
+
color: {
|
|
40
|
+
default: colors.positiveForeground,
|
|
41
|
+
':hover': colors.positiveSolidHover
|
|
42
|
+
}
|
|
43
|
+
},
|
|
38
44
|
secondary: {
|
|
39
45
|
color: {
|
|
40
46
|
default: colors.secondaryForeground,
|
|
@@ -10,7 +10,7 @@ export function SignInScreen() {
|
|
|
10
10
|
const appSettings = useModel('appSettings');
|
|
11
11
|
const signIn = useModel('signIn');
|
|
12
12
|
const isBusy = signIn.signingIn !== null;
|
|
13
|
-
return (_jsx("main", { ...stylex.props(styles.page), children: _jsxs("div", { ...stylex.props(styles.column), children: [_jsx("span", { ...stylex.props(styles.mark), children: _jsx(Text, { variant: "title", children: appSettings.title.charAt(0) }) }), _jsxs(Text, { as: "h1", variant: "title", tone: "primary", align: "center", children: ["Sign in to ", appSettings.title] }), signIn.step === 'choose' ? (_jsxs(_Fragment, { children: [_jsx(Button, { size: "lg", disabled: isBusy, isPending: signIn.signingIn === 'google', onClick: signIn.continueWithGoogle, children: "Continue with Google" }), _jsxs(Form, { onSubmit: (values) => signIn.sendEmailCode({ email: values['email'] ?? '' }), children: [_jsx(TextField, { name: "email", type: "email",
|
|
13
|
+
return (_jsx("main", { ...stylex.props(styles.page), children: _jsxs("div", { ...stylex.props(styles.column), children: [_jsx("span", { ...stylex.props(styles.mark), children: _jsx(Text, { variant: "title", children: appSettings.title.charAt(0) }) }), _jsxs(Text, { as: "h1", variant: "title", tone: "primary", align: "center", children: ["Sign in to ", appSettings.title] }), signIn.step === 'choose' ? (_jsxs(_Fragment, { children: [_jsx(Button, { size: "lg", disabled: isBusy, isPending: signIn.signingIn === 'google', onClick: signIn.continueWithGoogle, children: "Continue with Google" }), _jsxs(Form, { onSubmit: (values) => signIn.sendEmailCode({ email: values['email'] ?? '' }), children: [_jsx(TextField, { name: "email", type: "email", autoComplete: "email", placeholder: "you@example.com", label: "Email", isLabelHidden: true, size: "lg", disabled: true }), _jsx(Button, { type: "submit", variant: "secondary", size: "lg", disabled: true, children: "Email me a code" }), _jsx(Text, { variant: "caption", tone: "tertiary", align: "center", children: "Email sign-in coming soon" })] }), import.meta.env.DEV ? (_jsxs(Button, { variant: "tertiary", size: "lg", disabled: isBusy, isPending: signIn.signingIn === 'dev', onClick: () => signIn.signInAsDevUser({ email: DEV_USER }), children: ["Dev: sign in as ", DEV_USER] })) : null] })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { as: "p", tone: "secondary", align: "center", children: ["We sent a 6-digit code to ", signIn.email, "."] }), _jsxs(Form, { onSubmit: (values) => signIn.verifyEmailCode({ code: values['code'] ?? '' }), children: [_jsx(TextField, { name: "code", required: true, autoFocus: true, inputMode: "numeric", autoComplete: "one-time-code", pattern: "[0-9]{6}", maxLength: 6, placeholder: "123456", label: "Code", isLabelHidden: true, size: "lg" }), _jsx(Button, { type: "submit", size: "lg", disabled: isBusy, isPending: signIn.signingIn === 'email', children: "Sign in" })] }), _jsx(Button, { variant: "transparent", size: "lg", disabled: isBusy, onClick: signIn.startOver, children: "Use a different email" })] })), signIn.notice === null ? null : (_jsx(Text, { as: "p", tone: "secondary", align: "center", children: signIn.notice })), _jsx(Text, { as: "p", variant: "caption", tone: "tertiary", align: "center", children: "Sign-in by Pattern" })] }) }));
|
|
14
14
|
}
|
|
15
15
|
const DEV_USER = 'ada@acme.test';
|
|
16
16
|
const styles = stylex.create({
|
|
@@ -14,7 +14,7 @@ export function TextField({ label, isLabelHidden = false, description, error, on
|
|
|
14
14
|
if (event.currentTarget.value !== valueOnFocus.current) {
|
|
15
15
|
interact({ primitive: 'TextField', event: 'change', label });
|
|
16
16
|
}
|
|
17
|
-
}, className: stylex.props(styles.input, controlSizes[size], isInvalid && styles.invalid).className }), description === undefined ? null : (_jsx(Field.Description, { className: stylex.props(styles.note).className, children: description })), error === undefined ? null : (_jsx(Field.Error, { match: true, className: stylex.props(styles.error).className, children: error }))] }));
|
|
17
|
+
}, className: stylex.props(styles.input, controlSizes[size], isInvalid && styles.invalid, input.disabled === true && styles.disabled).className }), description === undefined ? null : (_jsx(Field.Description, { className: stylex.props(styles.note).className, children: description })), error === undefined ? null : (_jsx(Field.Error, { match: true, className: stylex.props(styles.error).className, children: error }))] }));
|
|
18
18
|
}
|
|
19
19
|
const focusRing = `inset 0 0 0 ${borders.hairline} ${colors.brandBorderFocus}, 0 0 0 ${borders.thin} ${colors.brandBorderFocus}, ${shadows.default}`;
|
|
20
20
|
const invalidRing = `inset 0 0 0 ${borders.hairline} ${colors.dangerBorderDefault}, 0 0 0 ${borders.thin} ${colors.dangerBorderDefault}, ${shadows.default}`;
|
|
@@ -55,6 +55,15 @@ const styles = stylex.create({
|
|
|
55
55
|
':focus-visible': invalidRing
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
|
+
disabled: {
|
|
59
|
+
color: colors.disabledForeground,
|
|
60
|
+
cursor: 'not-allowed',
|
|
61
|
+
backgroundColor: colors.disabled,
|
|
62
|
+
boxShadow: 'none',
|
|
63
|
+
'::placeholder': {
|
|
64
|
+
color: colors.disabledForeground
|
|
65
|
+
}
|
|
66
|
+
},
|
|
58
67
|
note: {
|
|
59
68
|
fontSize: fontSizes.captionLg,
|
|
60
69
|
lineHeight: lineHeights.caption,
|
package/dist/publishWire.d.ts
CHANGED
|
@@ -99,6 +99,18 @@ export declare const loginToApprove: z.ZodObject<{
|
|
|
99
99
|
code: z.ZodString;
|
|
100
100
|
label: z.ZodString;
|
|
101
101
|
}, z.core.$strip>;
|
|
102
|
+
export declare const setupCode: z.ZodObject<{
|
|
103
|
+
code: z.ZodString;
|
|
104
|
+
expiresAt: z.ZodString;
|
|
105
|
+
}, z.core.$strip>;
|
|
106
|
+
export declare const setupCodeExchanged: z.ZodObject<{
|
|
107
|
+
cookie: z.ZodString;
|
|
108
|
+
}, z.core.$strip>;
|
|
109
|
+
export declare const connection: z.ZodObject<{
|
|
110
|
+
label: z.ZodString;
|
|
111
|
+
connectedAt: z.ZodString;
|
|
112
|
+
}, z.core.$strip>;
|
|
113
|
+
export type Connection = z.output<typeof connection>;
|
|
102
114
|
export declare const publishServices: {
|
|
103
115
|
readonly apps: {
|
|
104
116
|
readonly list: NoInfer<import("./services.ts").ServiceCall<"/apps", {}, z.ZodArray<z.ZodObject<{
|
|
@@ -259,6 +271,19 @@ export declare const publishServices: {
|
|
|
259
271
|
finishedAt: z.ZodNullable<z.ZodString>;
|
|
260
272
|
}, z.core.$strip>>>;
|
|
261
273
|
};
|
|
274
|
+
readonly setup: {
|
|
275
|
+
readonly newCode: NoInfer<import("./services.ts").ServiceCall<"/apps/:name/setup-code", {}, z.ZodObject<{
|
|
276
|
+
code: z.ZodString;
|
|
277
|
+
expiresAt: z.ZodString;
|
|
278
|
+
}, z.core.$strip>>>;
|
|
279
|
+
readonly connection: NoInfer<import("./services.ts").ServiceCall<"/apps/:name/connection", {}, z.ZodNullable<z.ZodObject<{
|
|
280
|
+
label: z.ZodString;
|
|
281
|
+
connectedAt: z.ZodString;
|
|
282
|
+
}, z.core.$strip>>>>;
|
|
283
|
+
readonly disconnect: NoInfer<import("./services.ts").ServiceCall<"/apps/:name/connection/disconnect", {}, z.ZodObject<{
|
|
284
|
+
ok: z.ZodBoolean;
|
|
285
|
+
}, z.core.$strip>>>;
|
|
286
|
+
};
|
|
262
287
|
readonly logins: {
|
|
263
288
|
readonly read: NoInfer<import("./services.ts").ServiceCall<"/cli/logins/:approval", {}, z.ZodObject<{
|
|
264
289
|
code: z.ZodString;
|
package/dist/publishWire.js
CHANGED
|
@@ -126,6 +126,12 @@ export const loginPoll = z.union([
|
|
|
126
126
|
z.object({ status: z.literal('approved'), cookie: z.string() })
|
|
127
127
|
]);
|
|
128
128
|
export const loginToApprove = z.object({ code: z.string(), label: z.string() });
|
|
129
|
+
export const setupCode = z.object({ code: z.string(), expiresAt: z.string() });
|
|
130
|
+
export const setupCodeExchanged = z.object({ cookie: z.string() });
|
|
131
|
+
export const connection = z.object({
|
|
132
|
+
label: z.string(),
|
|
133
|
+
connectedAt: z.string()
|
|
134
|
+
});
|
|
129
135
|
export const publishServices = defineServices({
|
|
130
136
|
apps: {
|
|
131
137
|
list: call({ get: '/apps', reply: z.array(appSummary) }),
|
|
@@ -158,6 +164,17 @@ export const publishServices = defineServices({
|
|
|
158
164
|
reply: publishSummary
|
|
159
165
|
})
|
|
160
166
|
},
|
|
167
|
+
setup: {
|
|
168
|
+
newCode: call({ post: '/apps/:name/setup-code', reply: setupCode }),
|
|
169
|
+
connection: call({
|
|
170
|
+
get: '/apps/:name/connection',
|
|
171
|
+
reply: connection.nullable()
|
|
172
|
+
}),
|
|
173
|
+
disconnect: call({
|
|
174
|
+
post: '/apps/:name/connection/disconnect',
|
|
175
|
+
reply: z.object({ ok: z.boolean() })
|
|
176
|
+
})
|
|
177
|
+
},
|
|
161
178
|
logins: {
|
|
162
179
|
read: call({ get: '/cli/logins/:approval', reply: loginToApprove }),
|
|
163
180
|
approve: call({
|
package/dist/react.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { AppProvider, useModel } from './hooks/appContext.ts';
|
|
2
2
|
export { AppFrame } from './components/AppFrame.tsx';
|
|
3
|
+
export { Appear } from './components/Appear.tsx';
|
|
3
4
|
export { AppearancePicker } from './components/AppearancePicker.tsx';
|
|
4
5
|
export { Avatar } from './components/Avatar.tsx';
|
|
5
6
|
export { Badge } from './components/Badge.tsx';
|
package/dist/react.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { AppProvider, useModel } from "./hooks/appContext.js";
|
|
2
2
|
export { AppFrame } from "./components/AppFrame.js";
|
|
3
|
+
export { Appear } from "./components/Appear.js";
|
|
3
4
|
export { AppearancePicker } from "./components/AppearancePicker.js";
|
|
4
5
|
export { Avatar } from "./components/Avatar.js";
|
|
5
6
|
export { Badge } from "./components/Badge.js";
|
package/dist/rules/lintPlugin.js
CHANGED
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);
|