@byline/cli 5.0.0 → 5.1.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"server-ts.d.ts","sourceRoot":"","sources":["../../../src/phases/wire/server-ts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAiB,MAAM,aAAa,CAAA;AAQzD,eAAO,MAAM,YAAY,EAAE,OAS1B,CAAA"}
1
+ {"version":3,"file":"server-ts.d.ts","sourceRoot":"","sources":["../../../src/phases/wire/server-ts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAiB,MAAM,aAAa,CAAA;AAezD,eAAO,MAAM,YAAY,EAAE,OAS1B,CAAA"}
@@ -1,13 +1,20 @@
1
- import { existsSync, readFileSync } from 'node:fs';
2
- import { Project } from 'ts-morph';
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { Project, SyntaxKind } from 'ts-morph';
3
3
  const REL = 'src/server.ts';
4
4
  const IMPORT_SPECIFIER = '../byline/server.config';
5
5
  const SNIPPET = `// Initialize Byline server config (DB adapter, etc.) before handling any requests.
6
6
  import '${IMPORT_SPECIFIER}'
7
+ import { getBylineCore } from '@byline/core'
8
+ import { startBylineScheduler } from '@byline/core/scheduler'
9
+ declare global {
10
+ // biome-ignore lint: globalThis augmentation requires var rather than let
11
+ var __bylineSchedulerController__: ReturnType<typeof startBylineScheduler> | undefined
12
+ }
13
+ globalThis.__bylineSchedulerController__ ??= startBylineScheduler(getBylineCore())
7
14
  `;
8
15
  export const wireServerTs = {
9
16
  key: 'server-ts',
10
- title: `Inject side-effect import into ${REL}`,
17
+ title: `Initialize Byline and start its scheduler in ${REL}`,
11
18
  async preview(ctx) {
12
19
  return run(ctx, true);
13
20
  },
@@ -21,29 +28,77 @@ async function run(ctx, dryRun) {
21
28
  return { status: 'blocked', message: `${REL} not found — host phase should have caught this` };
22
29
  }
23
30
  const text = readFileSync(path, 'utf8');
24
- if (hasImport(text, IMPORT_SPECIFIER)) {
25
- return { status: 'skipped', message: `${REL}: side-effect import already present` };
26
- }
27
- if (dryRun) {
28
- return { status: 'done', message: `${REL}: will inject \`import '${IMPORT_SPECIFIER}'\`` };
29
- }
30
- const project = new Project({ useInMemoryFileSystem: false, skipAddingFilesFromTsConfig: true });
31
+ const project = new Project({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
31
32
  let source;
32
33
  try {
33
- source = project.addSourceFileAtPath(path);
34
+ source = project.createSourceFile('server.ts', text);
34
35
  }
35
36
  catch (_e) {
36
37
  return {
37
38
  status: 'manual',
38
- message: `${REL}: could not parse — please add the import manually`,
39
+ message: `${REL}: could not parse — please wire initialization and scheduler manually`,
39
40
  snippet: SNIPPET,
40
41
  };
41
42
  }
42
- // Place the side-effect import at the very top of the imports block so the
43
- // Byline runtime is registered before any other module side effects fire.
44
- source.insertImportDeclaration(0, { moduleSpecifier: IMPORT_SPECIFIER });
45
- source.saveSync();
46
- return { status: 'done', message: `${REL}: injected \`import '${IMPORT_SPECIFIER}'\`` };
43
+ let changed = false;
44
+ if (!hasImport(text, IMPORT_SPECIFIER)) {
45
+ source.insertImportDeclaration(0, { moduleSpecifier: IMPORT_SPECIFIER });
46
+ changed = true;
47
+ }
48
+ const schedulerImport = source
49
+ .getImportDeclarations()
50
+ .find((declaration) => declaration.getModuleSpecifierValue() === '@byline/core/scheduler');
51
+ const schedulerName = schedulerImport
52
+ ?.getNamedImports()
53
+ .find((item) => item.getName() === 'startBylineScheduler');
54
+ const localSchedulerName = schedulerName?.getAliasNode()?.getText() ?? schedulerName?.getName() ?? 'startBylineScheduler';
55
+ const alreadyStarted = schedulerName !== undefined &&
56
+ source
57
+ .getDescendantsOfKind(SyntaxKind.CallExpression)
58
+ .some((call) => call.getExpression().getText() === localSchedulerName);
59
+ if (!alreadyStarted) {
60
+ const coreGetter = ensureImport(source, '@byline/core', 'getBylineCore');
61
+ const scheduler = ensureImport(source, '@byline/core/scheduler', 'startBylineScheduler');
62
+ const declaration = source
63
+ .getDescendantsOfKind(SyntaxKind.VariableDeclaration)
64
+ .some((item) => item.getName() === '__bylineSchedulerController__');
65
+ source.addStatements(`
66
+ // Host-owned lifetime: config imports from seeds/migrations remain inert.
67
+ ${declaration
68
+ ? ''
69
+ : `declare global {
70
+ // biome-ignore lint: globalThis augmentation requires var rather than let
71
+ var __bylineSchedulerController__: ReturnType<typeof ${scheduler}> | undefined
72
+ }`}
73
+ globalThis.__bylineSchedulerController__ ??= ${scheduler}(${coreGetter}())
74
+ `);
75
+ changed = true;
76
+ }
77
+ if (!changed)
78
+ return {
79
+ status: 'skipped',
80
+ message: `${REL}: Byline initialization and scheduler already present`,
81
+ };
82
+ if (!dryRun) {
83
+ writeFileSync(path, source.getFullText());
84
+ }
85
+ return {
86
+ status: 'done',
87
+ message: `${REL}: ${dryRun ? 'will wire' : 'wired'} Byline initialization and scheduler`,
88
+ };
89
+ }
90
+ function ensureImport(source, moduleSpecifier, name) {
91
+ const declaration = source
92
+ .getImportDeclarations()
93
+ .find((item) => item.getModuleSpecifierValue() === moduleSpecifier && !item.isTypeOnly());
94
+ const existing = declaration?.getNamedImports().find((item) => item.getName() === name);
95
+ if (existing)
96
+ return existing.getAliasNode()?.getText() ?? existing.getName();
97
+ if (declaration)
98
+ declaration.addNamedImport(name);
99
+ else
100
+ source.addImportDeclaration({ moduleSpecifier, namedImports: [name] });
101
+ return name;
47
102
  }
48
103
  function hasImport(source, specifier) {
49
104
  // Match either form: with or without `.ts` extension, single or double quote.
@@ -1 +1 @@
1
- {"version":3,"file":"server-ts.js","sourceRoot":"","sources":["../../../src/phases/wire/server-ts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAElD,OAAO,EAAE,OAAO,EAAmB,MAAM,UAAU,CAAA;AAKnD,MAAM,GAAG,GAAG,eAAe,CAAA;AAC3B,MAAM,gBAAgB,GAAG,yBAAyB,CAAA;AAClD,MAAM,OAAO,GAAG;UACN,gBAAgB;CACzB,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAY;IACnC,GAAG,EAAE,WAAW;IAChB,KAAK,EAAE,kCAAkC,GAAG,EAAE;IAC9C,KAAK,CAAC,OAAO,CAAC,GAAG;QACf,OAAO,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACvB,CAAC;IACD,KAAK,CAAC,KAAK,CAAC,GAAG;QACb,OAAO,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACxB,CAAC;CACF,CAAA;AAED,KAAK,UAAU,GAAG,CAAC,GAAY,EAAE,MAAe;IAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAC7B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,GAAG,iDAAiD,EAAE,CAAA;IAChG,CAAC;IAED,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACvC,IAAI,SAAS,CAAC,IAAI,EAAE,gBAAgB,CAAC,EAAE,CAAC;QACtC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,GAAG,sCAAsC,EAAE,CAAA;IACrF,CAAC;IAED,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,2BAA2B,gBAAgB,KAAK,EAAE,CAAA;IAC5F,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,2BAA2B,EAAE,IAAI,EAAE,CAAC,CAAA;IAChG,IAAI,MAAkB,CAAA;IACtB,IAAI,CAAC;QACH,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAC5C,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;QACZ,OAAO;YACL,MAAM,EAAE,QAAQ;YAChB,OAAO,EAAE,GAAG,GAAG,oDAAoD;YACnE,OAAO,EAAE,OAAO;SACjB,CAAA;IACH,CAAC;IAED,2EAA2E;IAC3E,0EAA0E;IAC1E,MAAM,CAAC,uBAAuB,CAAC,CAAC,EAAE,EAAE,eAAe,EAAE,gBAAgB,EAAE,CAAC,CAAA;IACxE,MAAM,CAAC,QAAQ,EAAE,CAAA;IAEjB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,wBAAwB,gBAAgB,KAAK,EAAE,CAAA;AACzF,CAAC;AAED,SAAS,SAAS,CAAC,MAAc,EAAE,SAAiB;IAClD,8EAA8E;IAC9E,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAA;IAChE,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,iBAAiB,OAAO,gBAAgB,CAAC,CAAA;IAC/D,OAAO,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;AACxB,CAAC"}
1
+ {"version":3,"file":"server-ts.js","sourceRoot":"","sources":["../../../src/phases/wire/server-ts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=server-ts.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-ts.test.d.ts","sourceRoot":"","sources":["../../../src/phases/wire/server-ts.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { afterEach, describe, expect, it } from 'vitest';
3
+ import { createTestContext } from '../../test-helpers.js';
4
+ import { wireServerTs } from './server-ts.js';
5
+ const contexts = [];
6
+ afterEach(() => {
7
+ for (const ctx of contexts.splice(0))
8
+ rmSync(ctx.cwd, { recursive: true, force: true });
9
+ });
10
+ function fixture(text) {
11
+ const ctx = createTestContext();
12
+ contexts.push(ctx);
13
+ mkdirSync(ctx.resolve('src'), { recursive: true });
14
+ writeFileSync(ctx.resolve('src/server.ts'), text);
15
+ return ctx;
16
+ }
17
+ describe('host scheduler wiring', () => {
18
+ it('upgrades an existing config import, preserves the handler, and is idempotent', async () => {
19
+ const ctx = fixture("import '../byline/server.config.ts'\nexport default handler");
20
+ const original = readFileSync(ctx.resolve('src/server.ts'), 'utf8');
21
+ expect((await wireServerTs.preview(ctx)).status).toBe('done');
22
+ expect(readFileSync(ctx.resolve('src/server.ts'), 'utf8')).toBe(original);
23
+ expect((await wireServerTs.apply(ctx)).status).toBe('done');
24
+ const text = readFileSync(ctx.resolve('src/server.ts'), 'utf8');
25
+ expect(text).toContain('globalThis.__bylineSchedulerController__ ??= startBylineScheduler(getBylineCore())');
26
+ expect(text).toContain('export default handler');
27
+ expect((await wireServerTs.apply(ctx)).status).toBe('skipped');
28
+ expect(readFileSync(ctx.resolve('src/server.ts'), 'utf8')).toBe(text);
29
+ });
30
+ it('preserves an existing aliased scheduler startup', async () => {
31
+ const text = "import '../byline/server.config'\nimport { startBylineScheduler as start } from '@byline/core/scheduler'\nstart(core, { concurrency: 2 })";
32
+ const ctx = fixture(text);
33
+ expect((await wireServerTs.apply(ctx)).status).toBe('skipped');
34
+ expect(readFileSync(ctx.resolve('src/server.ts'), 'utf8')).toBe(text);
35
+ });
36
+ });
37
+ //# sourceMappingURL=server-ts.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-ts.test.js","sourceRoot":"","sources":["../../../src/phases/wire/server-ts.test.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,10 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
1
8
  import type { SubEdit } from './shared.js';
2
9
  export declare const wireStartTs: SubEdit;
3
10
  //# sourceMappingURL=start-ts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"start-ts.d.ts","sourceRoot":"","sources":["../../../src/phases/wire/start-ts.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAiB,MAAM,aAAa,CAAA;AAczD,eAAO,MAAM,WAAW,EAAE,OASzB,CAAA"}
1
+ {"version":3,"file":"start-ts.d.ts","sourceRoot":"","sources":["../../../src/phases/wire/start-ts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,OAAO,KAAK,EAAE,OAAO,EAAiB,MAAM,aAAa,CAAA;AAiBzD,eAAO,MAAM,WAAW,EAAE,OASzB,CAAA"}
@@ -1,14 +1,24 @@
1
- import { existsSync, readFileSync } from 'node:fs';
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { existsSync } from 'node:fs';
2
9
  import { Node, Project, SyntaxKind, } from 'ts-morph';
3
10
  const REL = 'src/start.ts';
4
11
  const ADAPTER_NAME = 'bylineCodedErrorAdapter';
5
12
  const ADAPTER_MODULE = '@byline/host-tanstack-start/integrations/start-errors';
6
- const SNIPPET = `import { createStart } from '@tanstack/react-start'
13
+ const SNIPPET = `import { createCsrfMiddleware, createStart } from '@tanstack/react-start'
7
14
 
8
15
  import { ${ADAPTER_NAME} } from '${ADAPTER_MODULE}'
16
+ import { passwordSignInMiddleware } from '@byline/host-tanstack-start/integrations/sign-in-middleware'
17
+ import { sessionRequestMiddleware } from '@byline/host-tanstack-start/integrations/session-request-middleware'
9
18
 
10
19
  export const startInstance = createStart(() => ({
11
20
  serializationAdapters: [${ADAPTER_NAME}],
21
+ requestMiddleware: [createCsrfMiddleware({ filter: (ctx) => ctx.handlerType === 'serverFn' }), sessionRequestMiddleware, passwordSignInMiddleware],
12
22
  }))
13
23
  `;
14
24
  export const wireStartTs = {
@@ -26,13 +36,6 @@ async function run(ctx, dryRun) {
26
36
  if (!existsSync(path)) {
27
37
  return { status: 'blocked', message: `${REL} not found — host phase should have caught this` };
28
38
  }
29
- const text = readFileSync(path, 'utf8');
30
- // Cheap pre-check: if the adapter identifier is already referenced anywhere,
31
- // assume the wiring is in place. Avoids a full AST round-trip on the common
32
- // case where wire has already been run.
33
- if (text.includes(ADAPTER_NAME)) {
34
- return { status: 'skipped', message: `${REL}: ${ADAPTER_NAME} already registered` };
35
- }
36
39
  const project = new Project({ useInMemoryFileSystem: false, skipAddingFilesFromTsConfig: true });
37
40
  let source;
38
41
  try {
@@ -49,13 +52,76 @@ async function run(ctx, dryRun) {
49
52
  if (!optionsLiteral) {
50
53
  return manualBail(`${REL}: \`createStart\` factory does not return an inline object literal — cannot safely auto-edit`);
51
54
  }
55
+ const middlewareProp = optionsLiteral.getProperty('requestMiddleware');
56
+ if (middlewareProp &&
57
+ (!Node.isPropertyAssignment(middlewareProp) ||
58
+ !Node.isArrayLiteralExpression(middlewareProp.getInitializer()))) {
59
+ return manualBail(`${REL}: requestMiddleware must be an inline array for safe editing`);
60
+ }
61
+ const arr = middlewareProp && Node.isPropertyAssignment(middlewareProp)
62
+ ? middlewareProp.getInitializerIfKindOrThrow(SyntaxKind.ArrayLiteralExpression)
63
+ : undefined;
64
+ const hasCsrf = arr?.getElements().some((el) => {
65
+ const expression = Node.isIdentifier(el)
66
+ ? source.getVariableDeclaration(el.getText())?.getInitializer()
67
+ : el;
68
+ return (expression &&
69
+ Node.isCallExpression(expression) &&
70
+ expression.getExpression().getText() === 'createCsrfMiddleware');
71
+ }) ?? false;
72
+ const hasSessionGuard = arr?.getElements().some((el) => el.getText() === 'sessionRequestMiddleware') ?? false;
73
+ const hasBodyGuard = arr?.getElements().some((el) => el.getText() === 'passwordSignInMiddleware') ?? false;
74
+ const adapterProp = optionsLiteral.getProperty('serializationAdapters');
75
+ const hasAdapter = adapterProp &&
76
+ Node.isPropertyAssignment(adapterProp) &&
77
+ adapterProp
78
+ .getInitializerIfKind(SyntaxKind.ArrayLiteralExpression)
79
+ ?.getElements()
80
+ .some((el) => el.getText() === ADAPTER_NAME);
81
+ if (hasCsrf && hasBodyGuard && hasSessionGuard && hasAdapter) {
82
+ return {
83
+ status: 'skipped',
84
+ message: `${REL}: sign-in protection and error serialization already registered`,
85
+ };
86
+ }
52
87
  if (dryRun) {
53
88
  return {
54
89
  status: 'done',
55
- message: `${REL}: will add ${ADAPTER_NAME} to serializationAdapters`,
90
+ message: `${REL}: will register sign-in protection and error serialization`,
56
91
  };
57
92
  }
58
93
  ensureImport(source);
94
+ for (const [moduleSpecifier, name] of [
95
+ ['@byline/host-tanstack-start/integrations/sign-in-middleware', 'passwordSignInMiddleware'],
96
+ ['@tanstack/react-start', 'createCsrfMiddleware'],
97
+ [
98
+ '@byline/host-tanstack-start/integrations/session-request-middleware',
99
+ 'sessionRequestMiddleware',
100
+ ],
101
+ ]) {
102
+ const declaration = source
103
+ .getImportDeclarations()
104
+ .find((d) => d.getModuleSpecifierValue() === moduleSpecifier);
105
+ if (!declaration)
106
+ source.addImportDeclaration({ moduleSpecifier: moduleSpecifier, namedImports: [name] });
107
+ else if (!declaration.getNamedImports().some((n) => n.getText() === name))
108
+ declaration.addNamedImport(name);
109
+ }
110
+ const csrf = "createCsrfMiddleware({ filter: (ctx) => ctx.handlerType === 'serverFn' })";
111
+ if (!arr) {
112
+ optionsLiteral.addPropertyAssignment({
113
+ name: 'requestMiddleware',
114
+ initializer: `[${csrf}, sessionRequestMiddleware, passwordSignInMiddleware]`,
115
+ });
116
+ }
117
+ else {
118
+ if (!hasCsrf)
119
+ arr.insertElement(0, csrf);
120
+ if (!hasSessionGuard)
121
+ arr.addElement('sessionRequestMiddleware');
122
+ if (!hasBodyGuard)
123
+ arr.addElement('passwordSignInMiddleware');
124
+ }
59
125
  ensureAdapterInOptions(optionsLiteral);
60
126
  source.saveSync();
61
127
  return { status: 'done', message: `${REL}: registered ${ADAPTER_NAME}` };
@@ -1 +1 @@
1
- {"version":3,"file":"start-ts.js","sourceRoot":"","sources":["../../../src/phases/wire/start-ts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"start-ts.js","sourceRoot":"","sources":["../../../src/phases/wire/start-ts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=start-ts.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-ts.test.d.ts","sourceRoot":"","sources":["../../../src/phases/wire/start-ts.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
9
+ import { afterEach, describe, expect, it } from 'vitest';
10
+ import { createTestContext } from '../../test-helpers.js';
11
+ import { wireStartTs } from './start-ts.js';
12
+ const contexts = [];
13
+ afterEach(() => {
14
+ for (const ctx of contexts.splice(0))
15
+ rmSync(ctx.cwd, { recursive: true, force: true });
16
+ });
17
+ function fixture(options) {
18
+ const ctx = createTestContext();
19
+ contexts.push(ctx);
20
+ mkdirSync(ctx.resolve('src'), { recursive: true });
21
+ writeFileSync(ctx.resolve('src/start.ts'), `import { createStart, createCsrfMiddleware } from '@tanstack/react-start'
22
+ import { bylineCodedErrorAdapter } from '@byline/host-tanstack-start/integrations/start-errors'
23
+ const csrf = createCsrfMiddleware({filter: ctx => ctx.handlerType === 'serverFn'})
24
+ export const startInstance = createStart(() => (${options}))`);
25
+ return ctx;
26
+ }
27
+ describe('Start sign-in middleware wiring', () => {
28
+ it('upgrades existing serialization-only wiring and is idempotent', async () => {
29
+ const ctx = fixture('{serializationAdapters:[bylineCodedErrorAdapter]}');
30
+ expect((await wireStartTs.apply(ctx)).status).toBe('done');
31
+ const text = readFileSync(ctx.resolve('src/start.ts'), 'utf8');
32
+ expect(text).toContain('requestMiddleware: [createCsrfMiddleware(');
33
+ expect(text).toContain('passwordSignInMiddleware]');
34
+ expect((await wireStartTs.apply(ctx)).status).toBe('skipped');
35
+ expect(readFileSync(ctx.resolve('src/start.ts'), 'utf8')).toBe(text);
36
+ });
37
+ it('preserves existing CSRF and unrelated middleware', async () => {
38
+ const ctx = fixture('{serializationAdapters:[bylineCodedErrorAdapter],requestMiddleware:[csrf, custom]}');
39
+ expect((await wireStartTs.apply(ctx)).status).toBe('done');
40
+ expect(readFileSync(ctx.resolve('src/start.ts'), 'utf8')).toContain('[csrf, custom, sessionRequestMiddleware, passwordSignInMiddleware]');
41
+ });
42
+ it('leaves computed middleware configuration for manual wiring', async () => {
43
+ const ctx = fixture('{requestMiddleware: buildMiddleware()}');
44
+ const original = readFileSync(ctx.resolve('src/start.ts'), 'utf8');
45
+ expect((await wireStartTs.preview(ctx)).status).toBe('manual');
46
+ expect((await wireStartTs.apply(ctx)).status).toBe('manual');
47
+ expect(readFileSync(ctx.resolve('src/start.ts'), 'utf8')).toBe(original);
48
+ });
49
+ });
50
+ //# sourceMappingURL=start-ts.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-ts.test.js","sourceRoot":"","sources":["../../../src/phases/wire/start-ts.test.ts"],"names":[],"mappings":"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"}
@@ -14,7 +14,9 @@
14
14
  */
15
15
 
16
16
  import { type AdminStore, registerAdminAbilities } from '@byline/admin'
17
- import { JwtSessionProvider } from '@byline/admin/auth'
17
+ import { createPasswordSignInLimiter, JwtSessionProvider } from '@byline/admin/auth'
18
+ import { getRequestIP } from '@tanstack/react-start/server'
19
+ import { createClientIpResolver } from '@byline/host-tanstack-start/integrations/client-ip'
18
20
  import { getAdminBylineClient } from '@byline/client/server'
19
21
  import { type BylineCore, initBylineCore } from '@byline/core'
20
22
  import { mysqlAdapter } from '@byline/db-mysql'
@@ -67,6 +69,8 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
67
69
  )
68
70
  }
69
71
 
72
+ const signInLimiter = createPasswordSignInLimiter(adminStore.signInRateLimits, signingSecret)
73
+
70
74
  const sessionProvider = new JwtSessionProvider({
71
75
  store: adminStore,
72
76
  signingSecret,
@@ -86,6 +90,16 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
86
90
  baseUrl: '/uploads',
87
91
  }),
88
92
  sessionProvider,
93
+ recurringTasks: [signInLimiter.cleanupTask],
94
+ passwordSignIn: {
95
+ limiter: signInLimiter,
96
+ resolveClientIp: createClientIpResolver({
97
+ // Opt in only when the proxy overwrites this header and direct access is blocked.
98
+ trustedProxyHeader: process.env.BYLINE_TRUSTED_CLIENT_IP_HEADER || undefined,
99
+ resolvePeerIp: () => getRequestIP() ??
100
+ (process.env.NODE_ENV === 'development' ? '127.0.0.1' : null),
101
+ }),
102
+ },
89
103
  fields: {
90
104
  richText: {
91
105
  embed: lexicalEditorEmbedServer({ getClient: getAdminBylineClient }),
@@ -11,7 +11,9 @@
11
11
  */
12
12
 
13
13
  import { type AdminStore, registerAdminAbilities } from '@byline/admin'
14
- import { JwtSessionProvider } from '@byline/admin/auth'
14
+ import { createPasswordSignInLimiter, JwtSessionProvider } from '@byline/admin/auth'
15
+ import { getRequestIP } from '@tanstack/react-start/server'
16
+ import { createClientIpResolver } from '@byline/host-tanstack-start/integrations/client-ip'
15
17
  import { getAdminBylineClient } from '@byline/client/server'
16
18
  import { type BylineCore, initBylineCore } from '@byline/core'
17
19
  import { mysqlAdapter } from '@byline/db-mysql'
@@ -75,6 +77,8 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
75
77
  )
76
78
  }
77
79
 
80
+ const signInLimiter = createPasswordSignInLimiter(adminStore.signInRateLimits, signingSecret)
81
+
78
82
  const sessionProvider = new JwtSessionProvider({
79
83
  store: adminStore,
80
84
  signingSecret,
@@ -94,6 +98,16 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
94
98
  baseUrl: '/uploads',
95
99
  }),
96
100
  sessionProvider,
101
+ recurringTasks: [signInLimiter.cleanupTask],
102
+ passwordSignIn: {
103
+ limiter: signInLimiter,
104
+ resolveClientIp: createClientIpResolver({
105
+ // Opt in only when the proxy overwrites this header and direct access is blocked.
106
+ trustedProxyHeader: process.env.BYLINE_TRUSTED_CLIENT_IP_HEADER || undefined,
107
+ resolvePeerIp: () => getRequestIP() ??
108
+ (process.env.NODE_ENV === 'development' ? '127.0.0.1' : null),
109
+ }),
110
+ },
97
111
  fields: {
98
112
  richText: {
99
113
  embed: lexicalEditorEmbedServer({ getClient: getAdminBylineClient }),
@@ -18,7 +18,9 @@
18
18
  */
19
19
 
20
20
  import { type AdminStore, registerAdminAbilities } from '@byline/admin'
21
- import { JwtSessionProvider } from '@byline/admin/auth'
21
+ import { createPasswordSignInLimiter, JwtSessionProvider } from '@byline/admin/auth'
22
+ import { getRequestIP } from '@tanstack/react-start/server'
23
+ import { createClientIpResolver } from '@byline/host-tanstack-start/integrations/client-ip'
22
24
  import { type BylineCore, initBylineCore } from '@byline/core'
23
25
  import { pgAdapter } from '@byline/db-postgres'
24
26
  import { createAdminStore } from '@byline/db-postgres/admin'
@@ -82,6 +84,8 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
82
84
  )
83
85
  }
84
86
 
87
+ const signInLimiter = createPasswordSignInLimiter(adminStore.signInRateLimits, signingSecret)
88
+
85
89
  const sessionProvider = new JwtSessionProvider({
86
90
  store: adminStore,
87
91
  signingSecret,
@@ -136,6 +140,16 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
136
140
  // cacheControl: 'public, max-age=31536000, immutable',
137
141
  // }),
138
142
  sessionProvider,
143
+ recurringTasks: [signInLimiter.cleanupTask],
144
+ passwordSignIn: {
145
+ limiter: signInLimiter,
146
+ resolveClientIp: createClientIpResolver({
147
+ // Opt in only when the proxy overwrites this header and direct access is blocked.
148
+ trustedProxyHeader: process.env.BYLINE_TRUSTED_CLIENT_IP_HEADER || undefined,
149
+ resolvePeerIp: () => getRequestIP() ??
150
+ (process.env.NODE_ENV === 'development' ? '127.0.0.1' : null),
151
+ }),
152
+ },
139
153
  fields: {
140
154
  richText: {
141
155
  embed: lexicalEditorEmbedServer({ getClient: getAdminBylineClient }),
@@ -15,7 +15,9 @@
15
15
  */
16
16
 
17
17
  import { type AdminStore, registerAdminAbilities } from '@byline/admin'
18
- import { JwtSessionProvider } from '@byline/admin/auth'
18
+ import { createPasswordSignInLimiter, JwtSessionProvider } from '@byline/admin/auth'
19
+ import { getRequestIP } from '@tanstack/react-start/server'
20
+ import { createClientIpResolver } from '@byline/host-tanstack-start/integrations/client-ip'
19
21
  import { type BylineCore, initBylineCore } from '@byline/core'
20
22
  import { pgAdapter } from '@byline/db-postgres'
21
23
  import { createAdminStore } from '@byline/db-postgres/admin'
@@ -130,6 +132,8 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
130
132
  )
131
133
  }
132
134
 
135
+ const signInLimiter = createPasswordSignInLimiter(adminStore.signInRateLimits, signingSecret)
136
+
133
137
  const sessionProvider = new JwtSessionProvider({
134
138
  store: adminStore,
135
139
  signingSecret,
@@ -190,6 +194,16 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
190
194
  // cacheControl: 'public, max-age=31536000, immutable',
191
195
  // }),
192
196
  sessionProvider,
197
+ recurringTasks: [signInLimiter.cleanupTask],
198
+ passwordSignIn: {
199
+ limiter: signInLimiter,
200
+ resolveClientIp: createClientIpResolver({
201
+ // Opt in only when the proxy overwrites this header and direct access is blocked.
202
+ trustedProxyHeader: process.env.BYLINE_TRUSTED_CLIENT_IP_HEADER || undefined,
203
+ resolvePeerIp: () => getRequestIP() ??
204
+ (process.env.NODE_ENV === 'development' ? '127.0.0.1' : null),
205
+ }),
206
+ },
193
207
  fields: {
194
208
  // Server-side richtext adapter — refreshes embedded relation
195
209
  // envelopes (link `{ title, path }`, inline-image `{ title, altText,
@@ -1,3 +1,12 @@
1
+ CREATE TABLE `byline_admin_login_sessions` (
2
+ `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
3
+ `admin_user_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
4
+ `session_version` int NOT NULL,
5
+ `expires_at` datetime(6) NOT NULL,
6
+ `revoked_at` datetime(6),
7
+ CONSTRAINT `byline_admin_login_sessions_id` PRIMARY KEY(`id`)
8
+ );
9
+ --> statement-breakpoint
1
10
  CREATE TABLE `byline_admin_permissions` (
2
11
  `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
3
12
  `vid` int NOT NULL DEFAULT 1,
@@ -12,7 +21,9 @@ CREATE TABLE `byline_admin_permissions` (
12
21
  CREATE TABLE `byline_admin_refresh_tokens` (
13
22
  `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
14
23
  `admin_user_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
24
+ `sid` char(36) CHARACTER SET ascii COLLATE ascii_bin,
15
25
  `token_hash` varchar(64) NOT NULL,
26
+ `session_version` int NOT NULL DEFAULT -1,
16
27
  `issued_at` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
17
28
  `expires_at` datetime(6) NOT NULL,
18
29
  `revoked_at` datetime(6),
@@ -46,6 +57,13 @@ CREATE TABLE `byline_admin_roles` (
46
57
  CONSTRAINT `byline_admin_roles_machine_name_unique` UNIQUE(`machine_name`)
47
58
  );
48
59
  --> statement-breakpoint
60
+ CREATE TABLE `byline_admin_sign_in_rate_limits` (
61
+ `key` varchar(64) NOT NULL,
62
+ `attempts` int NOT NULL,
63
+ `expires_at` datetime(3) NOT NULL,
64
+ CONSTRAINT `byline_admin_sign_in_rate_limits_key` PRIMARY KEY(`key`)
65
+ );
66
+ --> statement-breakpoint
49
67
  CREATE TABLE `byline_admin_user_preferences` (
50
68
  `user_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
51
69
  `scope` varchar(255) NOT NULL,
@@ -57,6 +75,7 @@ CREATE TABLE `byline_admin_user_preferences` (
57
75
  --> statement-breakpoint
58
76
  CREATE TABLE `byline_admin_users` (
59
77
  `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
78
+ `session_version` int NOT NULL DEFAULT 0,
60
79
  `vid` int NOT NULL DEFAULT 1,
61
80
  `given_name` varchar(100),
62
81
  `family_name` varchar(100),
@@ -377,7 +396,9 @@ CREATE TABLE `byline_store_text` (
377
396
  CONSTRAINT `unique_text_field` UNIQUE(`document_version_id`,`field_path`,`locale`)
378
397
  );
379
398
  --> statement-breakpoint
399
+ ALTER TABLE `byline_admin_login_sessions` ADD CONSTRAINT `fk_admin_login_sessions_user` FOREIGN KEY (`admin_user_id`) REFERENCES `byline_admin_users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
380
400
  ALTER TABLE `byline_admin_permissions` ADD CONSTRAINT `fk_admin_permissions_admin_role_id` FOREIGN KEY (`admin_role_id`) REFERENCES `byline_admin_roles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
401
+ ALTER TABLE `byline_admin_refresh_tokens` ADD CONSTRAINT `fk_admin_refresh_tokens_sid` FOREIGN KEY (`sid`) REFERENCES `byline_admin_login_sessions`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
381
402
  ALTER TABLE `byline_admin_refresh_tokens` ADD CONSTRAINT `fk_admin_refresh_tokens_admin_user_id` FOREIGN KEY (`admin_user_id`) REFERENCES `byline_admin_users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
382
403
  ALTER TABLE `byline_admin_role_admin_user` ADD CONSTRAINT `fk_admin_role_admin_user_admin_role_id` FOREIGN KEY (`admin_role_id`) REFERENCES `byline_admin_roles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
383
404
  ALTER TABLE `byline_admin_role_admin_user` ADD CONSTRAINT `fk_admin_role_admin_user_admin_user_id` FOREIGN KEY (`admin_user_id`) REFERENCES `byline_admin_users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
@@ -414,11 +435,14 @@ ALTER TABLE `byline_store_relation` ADD CONSTRAINT `fk_store_relation_target_col
414
435
  ALTER TABLE `byline_singleton_documents` ADD CONSTRAINT `fk_singleton_documents_document` FOREIGN KEY (`collection_id`,`document_id`) REFERENCES `byline_documents`(`collection_id`,`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
415
436
  ALTER TABLE `byline_store_text` ADD CONSTRAINT `fk_store_text_document_version_id` FOREIGN KEY (`document_version_id`) REFERENCES `byline_document_versions`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
416
437
  ALTER TABLE `byline_store_text` ADD CONSTRAINT `fk_store_text_collection_id` FOREIGN KEY (`collection_id`) REFERENCES `byline_collections`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
438
+ CREATE INDEX `idx_admin_login_sessions_user` ON `byline_admin_login_sessions` (`admin_user_id`);--> statement-breakpoint
417
439
  CREATE INDEX `idx_byline_admin_permissions_role` ON `byline_admin_permissions` (`admin_role_id`);--> statement-breakpoint
440
+ CREATE INDEX `idx_admin_refresh_tokens_sid` ON `byline_admin_refresh_tokens` (`sid`);--> statement-breakpoint
418
441
  CREATE INDEX `idx_byline_admin_refresh_tokens_user` ON `byline_admin_refresh_tokens` (`admin_user_id`);--> statement-breakpoint
419
442
  CREATE INDEX `idx_byline_admin_refresh_tokens_token_hash` ON `byline_admin_refresh_tokens` (`token_hash`);--> statement-breakpoint
420
443
  CREATE INDEX `idx_byline_admin_role_admin_user_user` ON `byline_admin_role_admin_user` (`admin_user_id`);--> statement-breakpoint
421
444
  CREATE INDEX `idx_byline_admin_roles_machine_name` ON `byline_admin_roles` (`machine_name`);--> statement-breakpoint
445
+ CREATE INDEX `idx_admin_sign_in_rate_limits_expiry` ON `byline_admin_sign_in_rate_limits` (`expires_at`);--> statement-breakpoint
422
446
  CREATE INDEX `idx_byline_admin_users_email` ON `byline_admin_users` (`email`);--> statement-breakpoint
423
447
  CREATE INDEX `idx_audit_log_document_id` ON `byline_audit_log` (`document_id`,`id`);--> statement-breakpoint
424
448
  CREATE INDEX `idx_audit_log_actor_id` ON `byline_audit_log` (`actor_id`,`id`);--> statement-breakpoint
@@ -5,8 +5,8 @@
5
5
  {
6
6
  "idx": 0,
7
7
  "version": "5",
8
- "when": 1788642356080,
9
- "tag": "0000_pale_bastion",
8
+ "when": 1788879988783,
9
+ "tag": "0000_kind_exodus",
10
10
  "breakpoints": true
11
11
  }
12
12
  ]
@@ -1,3 +1,11 @@
1
+ CREATE TABLE "byline_admin_login_sessions" (
2
+ "id" uuid PRIMARY KEY NOT NULL,
3
+ "admin_user_id" uuid NOT NULL,
4
+ "session_version" integer NOT NULL,
5
+ "expires_at" timestamp (6) with time zone NOT NULL,
6
+ "revoked_at" timestamp (6) with time zone
7
+ );
8
+ --> statement-breakpoint
1
9
  CREATE TABLE "byline_admin_permissions" (
2
10
  "id" uuid PRIMARY KEY NOT NULL,
3
11
  "vid" integer DEFAULT 1 NOT NULL,
@@ -11,7 +19,9 @@ CREATE TABLE "byline_admin_permissions" (
11
19
  CREATE TABLE "byline_admin_refresh_tokens" (
12
20
  "id" uuid PRIMARY KEY NOT NULL,
13
21
  "admin_user_id" uuid NOT NULL,
22
+ "sid" uuid,
14
23
  "token_hash" varchar(64) NOT NULL,
24
+ "session_version" integer DEFAULT -1 NOT NULL,
15
25
  "issued_at" timestamp (6) with time zone DEFAULT now() NOT NULL,
16
26
  "expires_at" timestamp (6) with time zone NOT NULL,
17
27
  "revoked_at" timestamp (6) with time zone,
@@ -43,6 +53,12 @@ CREATE TABLE "byline_admin_roles" (
43
53
  CONSTRAINT "byline_admin_roles_machine_name_unique" UNIQUE("machine_name")
44
54
  );
45
55
  --> statement-breakpoint
56
+ CREATE TABLE "byline_admin_sign_in_rate_limits" (
57
+ "key" varchar(64) PRIMARY KEY NOT NULL,
58
+ "attempts" integer NOT NULL,
59
+ "expires_at" timestamp (3) with time zone NOT NULL
60
+ );
61
+ --> statement-breakpoint
46
62
  CREATE TABLE "byline_admin_user_preferences" (
47
63
  "user_id" uuid NOT NULL,
48
64
  "scope" varchar(255) NOT NULL,
@@ -54,6 +70,7 @@ CREATE TABLE "byline_admin_user_preferences" (
54
70
  --> statement-breakpoint
55
71
  CREATE TABLE "byline_admin_users" (
56
72
  "id" uuid PRIMARY KEY NOT NULL,
73
+ "session_version" integer DEFAULT 0 NOT NULL,
57
74
  "vid" integer DEFAULT 1 NOT NULL,
58
75
  "given_name" varchar(100),
59
76
  "family_name" varchar(100),
@@ -356,8 +373,10 @@ CREATE TABLE "byline_store_text" (
356
373
  CONSTRAINT "unique_text_field" UNIQUE("document_version_id","field_path","locale")
357
374
  );
358
375
  --> statement-breakpoint
376
+ ALTER TABLE "byline_admin_login_sessions" ADD CONSTRAINT "byline_admin_login_sessions_admin_user_id_byline_admin_users_id_fk" FOREIGN KEY ("admin_user_id") REFERENCES "public"."byline_admin_users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
359
377
  ALTER TABLE "byline_admin_permissions" ADD CONSTRAINT "byline_admin_permissions_admin_role_id_byline_admin_roles_id_fk" FOREIGN KEY ("admin_role_id") REFERENCES "public"."byline_admin_roles"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
360
378
  ALTER TABLE "byline_admin_refresh_tokens" ADD CONSTRAINT "byline_admin_refresh_tokens_admin_user_id_byline_admin_users_id_fk" FOREIGN KEY ("admin_user_id") REFERENCES "public"."byline_admin_users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
379
+ ALTER TABLE "byline_admin_refresh_tokens" ADD CONSTRAINT "byline_admin_refresh_tokens_sid_byline_admin_login_sessions_id_fk" FOREIGN KEY ("sid") REFERENCES "public"."byline_admin_login_sessions"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
361
380
  ALTER TABLE "byline_admin_role_admin_user" ADD CONSTRAINT "byline_admin_role_admin_user_admin_role_id_byline_admin_roles_id_fk" FOREIGN KEY ("admin_role_id") REFERENCES "public"."byline_admin_roles"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
362
381
  ALTER TABLE "byline_admin_role_admin_user" ADD CONSTRAINT "byline_admin_role_admin_user_admin_user_id_byline_admin_users_id_fk" FOREIGN KEY ("admin_user_id") REFERENCES "public"."byline_admin_users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
363
382
  ALTER TABLE "byline_admin_user_preferences" ADD CONSTRAINT "byline_admin_user_preferences_user_id_byline_admin_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."byline_admin_users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
@@ -393,11 +412,14 @@ ALTER TABLE "byline_store_relation" ADD CONSTRAINT "byline_store_relation_target
393
412
  ALTER TABLE "byline_singleton_documents" ADD CONSTRAINT "fk_singleton_documents_document" FOREIGN KEY ("collection_id","document_id") REFERENCES "public"."byline_documents"("collection_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
394
413
  ALTER TABLE "byline_store_text" ADD CONSTRAINT "byline_store_text_document_version_id_byline_document_versions_id_fk" FOREIGN KEY ("document_version_id") REFERENCES "public"."byline_document_versions"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
395
414
  ALTER TABLE "byline_store_text" ADD CONSTRAINT "byline_store_text_collection_id_byline_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."byline_collections"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
415
+ CREATE INDEX "idx_admin_login_sessions_user" ON "byline_admin_login_sessions" USING btree ("admin_user_id");--> statement-breakpoint
396
416
  CREATE INDEX "idx_byline_admin_permissions_role" ON "byline_admin_permissions" USING btree ("admin_role_id");--> statement-breakpoint
417
+ CREATE INDEX "idx_admin_refresh_tokens_sid" ON "byline_admin_refresh_tokens" USING btree ("sid");--> statement-breakpoint
397
418
  CREATE INDEX "idx_byline_admin_refresh_tokens_user" ON "byline_admin_refresh_tokens" USING btree ("admin_user_id");--> statement-breakpoint
398
419
  CREATE INDEX "idx_byline_admin_refresh_tokens_token_hash" ON "byline_admin_refresh_tokens" USING btree ("token_hash");--> statement-breakpoint
399
420
  CREATE INDEX "idx_byline_admin_role_admin_user_user" ON "byline_admin_role_admin_user" USING btree ("admin_user_id");--> statement-breakpoint
400
421
  CREATE INDEX "idx_byline_admin_roles_machine_name" ON "byline_admin_roles" USING btree ("machine_name");--> statement-breakpoint
422
+ CREATE INDEX "idx_admin_sign_in_rate_limits_expiry" ON "byline_admin_sign_in_rate_limits" USING btree ("expires_at");--> statement-breakpoint
401
423
  CREATE INDEX "idx_byline_admin_users_email" ON "byline_admin_users" USING btree ("email");--> statement-breakpoint
402
424
  CREATE INDEX "idx_audit_log_document_id" ON "byline_audit_log" USING btree ("document_id","id");--> statement-breakpoint
403
425
  CREATE INDEX "idx_audit_log_actor_id" ON "byline_audit_log" USING btree ("actor_id","id");--> statement-breakpoint
@@ -5,8 +5,8 @@
5
5
  {
6
6
  "idx": 0,
7
7
  "version": "7",
8
- "when": 1788642365591,
9
- "tag": "0000_yielding_vulture",
8
+ "when": 1788880329240,
9
+ "tag": "0000_lively_talisman",
10
10
  "breakpoints": true
11
11
  }
12
12
  ]
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@byline/cli",
3
3
  "private": false,
4
4
  "license": "MPL-2.0",
5
- "version": "5.0.0",
5
+ "version": "5.1.1",
6
6
  "engines": {
7
7
  "node": ">=20.9.0"
8
8
  },
@@ -33,14 +33,14 @@
33
33
  "dist"
34
34
  ],
35
35
  "dependencies": {
36
- "@clack/prompts": "^1.7.0",
36
+ "@clack/prompts": "^1.8.0",
37
37
  "commander": "^15.0.0",
38
38
  "diff": "^9.0.0",
39
39
  "drizzle-orm": "^0.45.2",
40
40
  "execa": "^10.0.1",
41
41
  "jsonc-parser": "^3.3.1",
42
42
  "minimatch": "^10.2.6",
43
- "mysql2": "^3.24.2",
43
+ "mysql2": "^3.24.4",
44
44
  "pg": "^8.23.0",
45
45
  "picocolors": "^1.1.1",
46
46
  "semver": "^7.8.5",
@@ -48,20 +48,20 @@
48
48
  "yaml": "^2.9.0"
49
49
  },
50
50
  "devDependencies": {
51
- "@biomejs/biome": "2.5.10",
51
+ "@biomejs/biome": "2.5.12",
52
52
  "@types/mdast": "^4.0.4",
53
- "@types/node": "^26.4.0",
53
+ "@types/node": "^26.5.0",
54
54
  "@types/pg": "^8.23.1",
55
55
  "@types/semver": "^7.8.0",
56
56
  "dotenv": "^17.4.2",
57
57
  "mdast-util-to-string": "^4.0.0",
58
58
  "remark-gfm": "^4.0.1",
59
59
  "remark-parse": "^11.0.0",
60
- "tsc-alias": "^1.9.2",
60
+ "tsc-alias": "^1.9.4",
61
61
  "typescript": "^7.0.2",
62
62
  "unified": "^11.0.5",
63
- "vitest": "^4.1.11",
64
- "@byline/core": "5.0.0"
63
+ "vitest": "^5.0.0",
64
+ "@byline/core": "5.1.1"
65
65
  },
66
66
  "publishConfig": {
67
67
  "access": "public",