@byline/cli 4.19.0 → 5.1.0

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.
Files changed (34) hide show
  1. package/dist/lib/copied-script-drift.test.d.ts +2 -0
  2. package/dist/lib/copied-script-drift.test.d.ts.map +1 -0
  3. package/dist/lib/copied-script-drift.test.js +37 -0
  4. package/dist/lib/copied-script-drift.test.js.map +1 -0
  5. package/dist/phases/wire/server-ts.d.ts.map +1 -1
  6. package/dist/phases/wire/server-ts.js +72 -17
  7. package/dist/phases/wire/server-ts.js.map +1 -1
  8. package/dist/phases/wire/server-ts.test.d.ts +2 -0
  9. package/dist/phases/wire/server-ts.test.d.ts.map +1 -0
  10. package/dist/phases/wire/server-ts.test.js +37 -0
  11. package/dist/phases/wire/server-ts.test.js.map +1 -0
  12. package/dist/phases/wire/start-ts.d.ts +7 -0
  13. package/dist/phases/wire/start-ts.d.ts.map +1 -1
  14. package/dist/phases/wire/start-ts.js +76 -10
  15. package/dist/phases/wire/start-ts.js.map +1 -1
  16. package/dist/phases/wire/start-ts.test.d.ts +9 -0
  17. package/dist/phases/wire/start-ts.test.d.ts.map +1 -0
  18. package/dist/phases/wire/start-ts.test.js +50 -0
  19. package/dist/phases/wire/start-ts.test.js.map +1 -0
  20. package/dist/templates/byline-examples/scripts/import-docs.ts +13 -19
  21. package/dist/templates/byline-examples/scripts/lib/walk-document-status.ts +21 -0
  22. package/dist/templates/byline-examples/scripts/regenerate-media-operation.ts +17 -69
  23. package/dist/templates/byline-examples/scripts/regenerate-media.ts +20 -23
  24. package/dist/templates/byline-examples/seeds/site-settings.ts +10 -7
  25. package/dist/templates/dialects/mysql/byline/server.config.ts +15 -1
  26. package/dist/templates/dialects/mysql/byline-examples/server.config.ts +15 -1
  27. package/dist/templates/dialects/postgres/byline/server.config.ts +15 -1
  28. package/dist/templates/dialects/postgres/byline-examples/scripts/re-anchor.ts +15 -2
  29. package/dist/templates/dialects/postgres/byline-examples/server.config.ts +15 -1
  30. package/dist/templates/migrations/mysql/{0000_clean_magdalene.sql → 0000_kind_exodus.sql} +30 -2
  31. package/dist/templates/migrations/mysql/meta/_journal.json +2 -2
  32. package/dist/templates/migrations/postgres/{0000_quiet_johnny_blaze.sql → 0000_lively_talisman.sql} +28 -2
  33. package/dist/templates/migrations/postgres/meta/_journal.json +2 -2
  34. package/package.json +8 -8
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=copied-script-drift.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copied-script-drift.test.d.ts","sourceRoot":"","sources":["../../src/lib/copied-script-drift.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { dirname, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { describe, expect, it } from 'vitest';
5
+ const here = dirname(fileURLToPath(import.meta.url));
6
+ const cliTemplates = resolve(here, '../templates');
7
+ const webappByline = resolve(here, '../../../../apps/webapp/byline');
8
+ const exactCopies = [
9
+ {
10
+ name: 'media regeneration operation',
11
+ template: 'byline-examples/scripts/regenerate-media-operation.ts',
12
+ application: 'scripts/regenerate-media-operation.ts',
13
+ },
14
+ {
15
+ name: 'media regeneration caller',
16
+ template: 'byline-examples/scripts/regenerate-media.ts',
17
+ application: 'scripts/regenerate-media.ts',
18
+ },
19
+ {
20
+ name: 'PostgreSQL source-locale re-anchor script',
21
+ template: 'dialects/postgres/byline-examples/scripts/re-anchor.ts',
22
+ application: 'scripts/re-anchor.ts',
23
+ },
24
+ {
25
+ name: 'singleton seed',
26
+ template: 'byline-examples/seeds/site-settings.ts',
27
+ application: 'seeds/site-settings.ts',
28
+ },
29
+ ];
30
+ describe('R01 copied maintenance scripts', () => {
31
+ for (const copy of exactCopies) {
32
+ it(`keeps the ${copy.name} byte-for-byte equal to its application copy`, () => {
33
+ expect(readFileSync(resolve(webappByline, copy.application), 'utf8')).toBe(readFileSync(resolve(cliTemplates, copy.template), 'utf8'));
34
+ });
35
+ }
36
+ });
37
+ //# sourceMappingURL=copied-script-drift.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copied-script-drift.test.js","sourceRoot":"","sources":["../../src/lib/copied-script-drift.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACpD,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAA;AAClD,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,EAAE,gCAAgC,CAAC,CAAA;AAEpE,MAAM,WAAW,GAAG;IAClB;QACE,IAAI,EAAE,8BAA8B;QACpC,QAAQ,EAAE,uDAAuD;QACjE,WAAW,EAAE,uCAAuC;KACrD;IACD;QACE,IAAI,EAAE,2BAA2B;QACjC,QAAQ,EAAE,6CAA6C;QACvD,WAAW,EAAE,6BAA6B;KAC3C;IACD;QACE,IAAI,EAAE,2CAA2C;QACjD,QAAQ,EAAE,wDAAwD;QAClE,WAAW,EAAE,sBAAsB;KACpC;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,QAAQ,EAAE,wCAAwC;QAClD,WAAW,EAAE,wBAAwB;KACtC;CACO,CAAA;AAEV,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,EAAE,CAAC,aAAa,IAAI,CAAC,IAAI,8CAA8C,EAAE,GAAG,EAAE;YAC5E,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CACxE,YAAY,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAC3D,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAC,CAAA"}
@@ -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":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAExE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAG3C,MAAM,QAAQ,GAAc,EAAE,CAAA;AAC9B,SAAS,CAAC,GAAG,EAAE;IACb,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AACzF,CAAC,CAAC,CAAA;AACF,SAAS,OAAO,CAAC,OAAe;IAC9B,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAA;IAC/B,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAClD,aAAa,CACX,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,EAC3B;;;kDAG8C,OAAO,IAAI,CAC1D,CAAA;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AACD,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,GAAG,GAAG,OAAO,CAAC,mDAAmD,CAAC,CAAA;QACxE,MAAM,CAAC,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC1D,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,CAAA;QAC9D,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,2CAA2C,CAAC,CAAA;QACnE,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAA;QACnD,MAAM,CAAC,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC7D,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACtE,CAAC,CAAC,CAAA;IACF,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,GAAG,GAAG,OAAO,CACjB,oFAAoF,CACrF,CAAA;QACD,MAAM,CAAC,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC1D,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CACjE,oEAAoE,CACrE,CAAA;IACH,CAAC,CAAC,CAAA;IACF,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,MAAM,GAAG,GAAG,OAAO,CAAC,wCAAwC,CAAC,CAAA;QAC7D,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,CAAA;QAClE,MAAM,CAAC,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC9D,MAAM,CAAC,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC5D,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { walkToStatus } from './lib/walk-document-status.js'
1
2
  /**
2
3
  * This Source Code is subject to the terms of the Mozilla Public
3
4
  * License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -185,25 +186,13 @@ function derivePath(frontmatter: DocFrontmatter, locale: string): string {
185
186
  * through any intermediate statuses (e.g. needs_review). No-op when the
186
187
  * workflow doesn't include the target or when already at/past it.
187
188
  */
188
- async function walkToStatus(
189
- handle: DocsHandle,
190
- documentId: string,
191
- workflowStatuses: readonly { name: string }[],
192
- currentStatus: string,
193
- targetStatus: string
194
- ): Promise<void> {
195
- const currentIdx = workflowStatuses.findIndex((s) => s.name === currentStatus)
196
- const targetIdx = workflowStatuses.findIndex((s) => s.name === targetStatus)
197
- if (currentIdx === -1 || targetIdx === -1 || targetIdx <= currentIdx) return
198
- for (let i = currentIdx + 1; i <= targetIdx; i++) {
199
- await handle.changeStatus(documentId, workflowStatuses[i].name)
200
- }
201
- }
189
+
202
190
 
203
191
  interface ProcessResult {
204
192
  filePath: string
205
193
  action: 'created' | 'updated' | 'skipped'
206
194
  documentId?: string
195
+ revision?: number
207
196
  path: string
208
197
  }
209
198
 
@@ -301,18 +290,22 @@ async function processFile(
301
290
  const workflowStatuses = definition?.workflow?.statuses ?? []
302
291
  const defaultStatus = workflowStatuses[0]?.name ?? 'draft'
303
292
 
304
- const existing = await handle.findByPath(docPath, {
293
+ const selected = await handle.findByPath(docPath, {
305
294
  locale,
306
295
  status: 'any',
307
296
  _bypassBeforeRead: true,
308
297
  })
309
298
 
299
+ const existing = selected == null ? null : await handle.findByIdForEdit(selected.id, { locale, _bypassBeforeRead: true })
300
+ if (selected != null && existing == null) throw new Error('Import target is no longer available; rerun the import.')
301
+
310
302
  if (existing) {
311
303
  // Don't clobber publishedOn if Byline already has one.
312
304
  if (existing.fields?.publishedOn) {
313
305
  delete payload.publishedOn
314
306
  }
315
307
  const result = await handle.update(existing.id, payload, {
308
+ expectedRevision: existing.revision,
316
309
  locale,
317
310
  // Advertise the imported locale (editorial available-locales set), merged
318
311
  // with whatever is already advertised so a later-locale re-import doesn't
@@ -320,8 +313,8 @@ async function processFile(
320
313
  // completeness ledger (intersection). See docs/08-internationalization/index.md.
321
314
  availableLocales: [...new Set([...(existing.availableLocales ?? []), locale])],
322
315
  })
323
- await walkToStatus(handle, result.documentId, workflowStatuses, defaultStatus, desiredStatus)
324
- return { filePath, action: 'updated', documentId: result.documentId, path: docPath }
316
+ const revision = await walkToStatus(handle, result.documentId, workflowStatuses, defaultStatus, desiredStatus, result.revision)
317
+ return { filePath, action: 'updated', documentId: result.documentId, revision, path: docPath }
325
318
  }
326
319
 
327
320
  const result = await handle.create(payload, {
@@ -332,7 +325,7 @@ async function processFile(
332
325
  // intersection of this editorial set with the completeness ledger.
333
326
  availableLocales: [locale],
334
327
  })
335
- return { filePath, action: 'created', documentId: result.documentId, path: docPath }
328
+ return { filePath, action: 'created', documentId: result.documentId, revision: result.revision, path: docPath }
336
329
  }
337
330
 
338
331
  /**
@@ -386,7 +379,8 @@ async function placeTreeFromDirectories(
386
379
  const groupKey = parentDocumentId ?? ROOT_GROUP
387
380
  const beforeDocumentId = lastSiblingByGroup.get(groupKey) ?? null
388
381
  try {
389
- await handle.placeTreeNode(r.documentId, { parentDocumentId, beforeDocumentId })
382
+ if (r.revision == null) throw new Error('Imported document has no observed revision')
383
+ await handle.placeTreeNode(r.documentId, { expectedRevision: r.revision, parentDocumentId, beforeDocumentId })
390
384
  lastSiblingByGroup.set(groupKey, r.documentId)
391
385
  if (parentDocumentId != null) {
392
386
  placed += 1
@@ -0,0 +1,21 @@
1
+ import type { CollectionHandle } from '@byline/client'
2
+
3
+ /** Preserve the revision returned by each successful workflow transition.
4
+ * A conflict terminates the walk; it never fetches a newer observation. */
5
+ export async function walkToStatus(
6
+ handle: Pick<CollectionHandle, 'changeStatus'>,
7
+ documentId: string,
8
+ workflowStatuses: readonly { name: string }[],
9
+ currentStatus: string,
10
+ targetStatus: string,
11
+ expectedRevision: number
12
+ ): Promise<number> {
13
+ const currentIdx = workflowStatuses.findIndex((s) => s.name === currentStatus)
14
+ const targetIdx = workflowStatuses.findIndex((s) => s.name === targetStatus)
15
+ if (currentIdx === -1 || targetIdx === -1 || targetIdx <= currentIdx) return expectedRevision
16
+ for (let i = currentIdx + 1; i <= targetIdx; i++) {
17
+ const result = await handle.changeStatus(documentId, workflowStatuses[i].name, { expectedRevision })
18
+ expectedRevision = result.revision
19
+ }
20
+ return expectedRevision
21
+ }