bunderstack 0.21.1 → 0.22.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.
- package/CHANGELOG.md +55 -0
- package/README.md +15 -10
- package/dist/api/builder.d.ts +2 -2
- package/dist/api/builder.js +1 -1
- package/dist/api/builder.js.map +1 -1
- package/dist/api/context.d.ts +4 -1
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +2 -0
- package/dist/api/context.js.map +1 -1
- package/dist/auth.d.ts +8 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +14 -0
- package/dist/auth.js.map +1 -1
- package/dist/backend-internals.d.ts +43 -0
- package/dist/backend-internals.d.ts.map +1 -0
- package/dist/backend-internals.js +2 -0
- package/dist/backend-internals.js.map +1 -0
- package/dist/backend.d.ts +26 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +58 -0
- package/dist/backend.js.map +1 -0
- package/dist/blueprint-generator.d.ts.map +1 -1
- package/dist/blueprint-generator.js +41 -51
- package/dist/blueprint-generator.js.map +1 -1
- package/dist/config.d.ts +0 -6
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/database/adapter.d.ts +10 -3
- package/dist/database/adapter.d.ts.map +1 -1
- package/dist/database/adapter.js.map +1 -1
- package/dist/database/bun-sql.d.ts.map +1 -1
- package/dist/database/bun-sql.js +1 -3
- package/dist/database/bun-sql.js.map +1 -1
- package/dist/database/bun-sqlite.d.ts +8 -0
- package/dist/database/bun-sqlite.d.ts.map +1 -0
- package/dist/database/bun-sqlite.js +56 -0
- package/dist/database/bun-sqlite.js.map +1 -0
- package/dist/database/libsql.d.ts.map +1 -1
- package/dist/database/libsql.js +25 -3
- package/dist/database/libsql.js.map +1 -1
- package/dist/database/pglite.d.ts.map +1 -1
- package/dist/database/pglite.js +25 -4
- package/dist/database/pglite.js.map +1 -1
- package/dist/database/postgres-js.d.ts.map +1 -1
- package/dist/database/postgres-js.js +1 -3
- package/dist/database/postgres-js.js.map +1 -1
- package/dist/db.d.ts +1 -2
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +5 -3
- package/dist/db.js.map +1 -1
- package/dist/email.d.ts +3 -1
- package/dist/email.d.ts.map +1 -1
- package/dist/email.js +9 -2
- package/dist/email.js.map +1 -1
- package/dist/env.d.ts +1 -1
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +1 -4
- package/dist/env.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +4 -2
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +3 -108
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -484
- package/dist/index.js.map +1 -1
- package/dist/jobs/define.d.ts +1 -1
- package/dist/jobs/define.d.ts.map +1 -1
- package/dist/jobs/define.js.map +1 -1
- package/dist/jobs/index.js +1 -1
- package/dist/jobs/index.js.map +1 -1
- package/dist/jobs/queue.d.ts +1 -1
- package/dist/jobs/queue.d.ts.map +1 -1
- package/dist/jobs/queue.js +1 -2
- package/dist/jobs/queue.js.map +1 -1
- package/dist/jobs/worker.d.ts +21 -0
- package/dist/jobs/worker.d.ts.map +1 -1
- package/dist/jobs/worker.js +64 -4
- package/dist/jobs/worker.js.map +1 -1
- package/dist/logging.d.ts +8 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +6 -0
- package/dist/logging.js.map +1 -0
- package/dist/provision-internals.d.ts +1 -1
- package/dist/provision-internals.js +1 -1
- package/dist/provision-internals.js.map +1 -1
- package/dist/provision.d.ts +2 -0
- package/dist/provision.d.ts.map +1 -1
- package/dist/provision.js +24 -3
- package/dist/provision.js.map +1 -1
- package/dist/query/infer.d.ts +1 -1
- package/dist/query/infer.d.ts.map +1 -1
- package/dist/query/infer.js.map +1 -1
- package/dist/runtime.d.ts +153 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +537 -0
- package/dist/runtime.js.map +1 -0
- package/dist/schema-export-pg.js +1 -1
- package/dist/schema-export-pg.js.map +1 -1
- package/dist/storage/background.d.ts +3 -0
- package/dist/storage/background.d.ts.map +1 -0
- package/dist/storage/background.js +3 -0
- package/dist/storage/background.js.map +1 -0
- package/dist/testing/auth.d.ts +85 -0
- package/dist/testing/auth.d.ts.map +1 -0
- package/dist/testing/auth.js +140 -0
- package/dist/testing/auth.js.map +1 -0
- package/dist/testing/client.d.ts +6 -0
- package/dist/testing/client.d.ts.map +1 -0
- package/dist/testing/client.js +9 -0
- package/dist/testing/client.js.map +1 -0
- package/dist/testing/database.d.ts +6 -0
- package/dist/testing/database.d.ts.map +1 -0
- package/dist/testing/database.js +8 -0
- package/dist/testing/database.js.map +1 -0
- package/dist/testing/email.d.ts +15 -0
- package/dist/testing/email.d.ts.map +1 -0
- package/dist/testing/email.js +32 -0
- package/dist/testing/email.js.map +1 -0
- package/dist/testing/fixture.d.ts +51 -0
- package/dist/testing/fixture.d.ts.map +1 -0
- package/dist/testing/fixture.js +178 -0
- package/dist/testing/fixture.js.map +1 -0
- package/dist/testing/jobs.d.ts +40 -0
- package/dist/testing/jobs.d.ts.map +1 -0
- package/dist/testing/jobs.js +76 -0
- package/dist/testing/jobs.js.map +1 -0
- package/dist/testing/logs.d.ts +18 -0
- package/dist/testing/logs.d.ts.map +1 -0
- package/dist/testing/logs.js +53 -0
- package/dist/testing/logs.js.map +1 -0
- package/dist/testing/storage.d.ts +7 -0
- package/dist/testing/storage.d.ts.map +1 -0
- package/dist/testing/storage.js +29 -0
- package/dist/testing/storage.js.map +1 -0
- package/dist/testing.d.ts +10 -26
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +3 -9
- package/dist/testing.js.map +1 -1
- package/llms.txt +51 -14
- package/package.json +23 -15
- package/skills/creating-bunderstack-apps/references/application-structure.md +16 -12
- package/skills/creating-bunderstack-apps/references/runtime-integrations.md +4 -1
- package/skills/migrating-to-bunderstack/SKILL.md +7 -6
- package/skills/migrating-to-bunderstack/references/audit-checklist.md +4 -4
- package/skills/migrating-to-bunderstack/references/runtime-replacements.md +55 -49
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixture.js","sourceRoot":"","sources":["../../src/testing/fixture.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdtemp, rm } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\n\nimport type { BunderstackBackend } from '../backend'\nimport type { AnyBunderstackApp, BunderstackClient } from '../client/rpc-client'\nimport type { TestDatabaseStrategy } from '../database/adapter'\nimport type { TestSchemaMode } from '../provision'\nimport type { TestAuth, TestIdentity } from './auth'\nimport type { TestEmail } from './email'\nimport type { TestLogs, TestLogMode } from './logs'\nimport type { TestStorage } from './storage'\n\nimport {\n BACKEND_INTERNALS,\n type RuntimeTestingHandle,\n} from '../backend-internals'\nimport { provisionForTest } from '../provision'\nimport { createTestAuth, createTestSessionRegistry } from './auth'\nimport { testClient } from './client'\nimport { createTestDatabaseTarget } from './database'\nimport { createTestEmail } from './email'\nimport { createTestJobs, type TestJobs } from './jobs'\nimport { createTestLogs } from './logs'\nimport { createTestStorage, resolveTestBuckets } from './storage'\n\nexport type TestOptions = {\n env?: Record<string, string | undefined>\n database?: {\n mode?: 'memory' | 'temporary'\n schema?: TestSchemaMode\n strategy?: TestDatabaseStrategy\n }\n logs?: TestLogMode\n}\n\nexport type TestCleanup = () => unknown | Promise<unknown>\n\nexport type TestSetup<TApp, TContext> = (\n fixture: TestFixture<TApp>,\n) => TContext | Promise<TContext>\n\nexport type TestConfigureOptions<TApp, TContext> = TestOptions & {\n setup?: TestSetup<TApp, TContext>\n}\n\nexport type TestFixture<TApp> = AsyncDisposable & {\n readonly app: TApp\n readonly auth: TestAuth\n readonly email: TestEmail\n readonly jobs: TestJobs\n readonly logs: TestLogs\n readonly storage: TestStorage\n defer(cleanup: TestCleanup): void\n client(\n identity?: TestIdentity,\n ): TApp extends AnyBunderstackApp ? BunderstackClient<TApp> : never\n close(): Promise<void>\n}\n\nexport type ConfiguredTestFixture<TApp, TContext> = TestFixture<TApp> & {\n readonly context: TContext\n}\n\nexport type TestFactory<TApp, TContext> = (\n options?: TestOptions,\n) => Promise<ConfiguredTestFixture<TApp, TContext>>\n\nexport type TestMethod<TApp> = {\n (options?: TestOptions): Promise<TestFixture<TApp>>\n configure<TContext = undefined>(\n options: TestConfigureOptions<TApp, TContext>,\n ): TestFactory<TApp, TContext>\n}\n\ntype TestableApp = {\n auth: unknown\n handler(request: Request): Promise<Response>\n close(): Promise<void>\n}\n\nconst defaultTestEnv = {\n NODE_ENV: 'test',\n AUTH_SECRET: 'bunderstack-test-secret',\n BUNDERSTACK_ROLE: 'web',\n} satisfies Record<string, string | undefined>\n\nfunction mergeTestOptions(\n defaults: TestOptions,\n overrides: TestOptions,\n): TestOptions {\n return {\n ...defaults,\n ...overrides,\n env:\n defaults.env || overrides.env\n ? { ...defaults.env, ...overrides.env }\n : undefined,\n database:\n defaults.database || overrides.database\n ? { ...defaults.database, ...overrides.database }\n : undefined,\n }\n}\n\nexport function configureTestApp<\n TApp extends TestableApp,\n TContext = undefined,\n>(\n backend: BunderstackBackend<TApp>,\n options: TestConfigureOptions<TApp, TContext>,\n): TestFactory<TApp, TContext> {\n const { setup, ...defaults } = options\n return async (overrides = {}) => {\n const fixture = await createTestApp(\n backend,\n mergeTestOptions(defaults, overrides),\n )\n try {\n const context = setup ? await setup(fixture) : (undefined as TContext)\n return Object.assign(fixture, { context })\n } catch (cause) {\n try {\n await fixture.close()\n } catch (cleanupCause) {\n throw new AggregateError(\n [cause, cleanupCause],\n '[bunderstack] test fixture setup and cleanup failed',\n )\n }\n throw cause\n }\n }\n}\n\nexport async function createTestApp<TApp extends TestableApp>(\n backend: BunderstackBackend<TApp>,\n options: TestOptions = {},\n): Promise<TestFixture<TApp>> {\n const internals = backend[BACKEND_INTERNALS]\n const storageRoot = await mkdtemp(join(tmpdir(), 'bunderstack-storage-'))\n const resolvedStorage = resolveTestBuckets(\n internals.declaration.config.storage,\n storageRoot,\n )\n const { adapter: emailAdapter, email } = createTestEmail()\n const storage = createTestStorage(resolvedStorage)\n const sessions = createTestSessionRegistry()\n const { logger, logs } = createTestLogs(options.logs)\n\n let target\n try {\n target = await createTestDatabaseTarget(\n internals.declaration.config.database.adapter,\n {\n mode: options.database?.mode ?? 'memory',\n strategy: options.database?.strategy,\n },\n )\n } catch (cause) {\n await rm(storageRoot, { recursive: true, force: true })\n throw cause\n }\n\n let app: TApp | undefined\n let testingHandle: RuntimeTestingHandle | undefined\n try {\n app = await internals.start(\n { ...defaultTestEnv, ...options.env },\n {\n database: target.connection,\n resolvedStorage,\n emailAdapter,\n authResolver: sessions.resolver,\n logger,\n forceMemoryRealtime: true,\n backgroundAutoStart: false,\n captureTestingHandle: (handle) => {\n testingHandle = handle\n },\n },\n )\n await provisionForTest(app as object, options.database?.schema ?? 'auto')\n } catch (cause) {\n const cleanupErrors: unknown[] = []\n if (app) {\n try {\n await app.close()\n } catch (error) {\n cleanupErrors.push(error)\n }\n }\n try {\n await target[Symbol.asyncDispose]()\n } catch (error) {\n cleanupErrors.push(error)\n }\n try {\n await rm(storageRoot, { recursive: true, force: true })\n } catch (error) {\n cleanupErrors.push(error)\n }\n if (cleanupErrors.length > 0) {\n throw new AggregateError(\n [cause, ...cleanupErrors],\n '[bunderstack] test fixture setup and cleanup failed',\n )\n }\n throw cause\n }\n\n if (!testingHandle) {\n await app.close()\n await target[Symbol.asyncDispose]()\n await rm(storageRoot, { recursive: true, force: true })\n throw new Error('[bunderstack] runtime did not provide test controls')\n }\n\n const auth = createTestAuth(app, email, sessions)\n const jobs = createTestJobs(testingHandle)\n const deferred: TestCleanup[] = []\n let closePromise: Promise<void> | undefined\n const defer = (cleanup: TestCleanup) => {\n if (closePromise) {\n throw new Error('[bunderstack] cannot defer cleanup after fixture close')\n }\n deferred.push(cleanup)\n }\n const close = () => {\n closePromise ??= (async () => {\n const errors: unknown[] = []\n for (const cleanup of deferred.reverse()) {\n try {\n await cleanup()\n } catch (error) {\n errors.push(error)\n }\n }\n try {\n await app.close()\n } catch (error) {\n errors.push(error)\n }\n try {\n await target[Symbol.asyncDispose]()\n } catch (error) {\n errors.push(error)\n }\n try {\n await rm(storageRoot, { recursive: true, force: true })\n } catch (error) {\n errors.push(error)\n }\n if (errors.length === 1) throw errors[0]\n if (errors.length > 1) {\n throw new AggregateError(errors, '[bunderstack] fixture cleanup failed')\n }\n })()\n return closePromise\n }\n\n return {\n app,\n auth,\n email,\n jobs,\n logs,\n storage,\n defer,\n client: (identity) => testClient(app as never, identity) as never,\n close,\n [Symbol.asyncDispose]: close,\n }\n}\n"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { RuntimeJobFailure, RuntimeTestJob, RuntimeTestingHandle } from '../backend-internals.js';
|
|
2
|
+
export type JobRunReport = {
|
|
3
|
+
ticks: number;
|
|
4
|
+
claimed: number;
|
|
5
|
+
ran: number;
|
|
6
|
+
failed: number;
|
|
7
|
+
remainingRunnable: number;
|
|
8
|
+
};
|
|
9
|
+
export type RunNextOptions = {
|
|
10
|
+
now?: Date | number;
|
|
11
|
+
};
|
|
12
|
+
export type RunUntilIdleOptions = RunNextOptions & {
|
|
13
|
+
maxTicks?: number;
|
|
14
|
+
failOnJobError?: boolean;
|
|
15
|
+
};
|
|
16
|
+
export type TestJob = Readonly<RuntimeTestJob>;
|
|
17
|
+
export type TestJobFilter = {
|
|
18
|
+
name?: string;
|
|
19
|
+
dedupeKey?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare class TestJobsError extends Error {
|
|
22
|
+
readonly report: JobRunReport;
|
|
23
|
+
readonly failures: RuntimeJobFailure[];
|
|
24
|
+
readonly name = "TestJobsError";
|
|
25
|
+
constructor(report: JobRunReport, failures: RuntimeJobFailure[]);
|
|
26
|
+
}
|
|
27
|
+
export declare class TestJobsConvergenceError extends Error {
|
|
28
|
+
readonly report: JobRunReport;
|
|
29
|
+
readonly name = "TestJobsConvergenceError";
|
|
30
|
+
constructor(report: JobRunReport);
|
|
31
|
+
}
|
|
32
|
+
export type TestJobs = {
|
|
33
|
+
runNext(options?: RunNextOptions): Promise<JobRunReport>;
|
|
34
|
+
runUntilIdle(options?: RunUntilIdleOptions): Promise<JobRunReport>;
|
|
35
|
+
inspect(filter?: TestJobFilter): Promise<readonly TestJob[]>;
|
|
36
|
+
pending(filter?: TestJobFilter): Promise<readonly TestJob[]>;
|
|
37
|
+
failed(filter?: TestJobFilter): Promise<readonly TestJob[]>;
|
|
38
|
+
};
|
|
39
|
+
export declare function createTestJobs(handle: RuntimeTestingHandle): TestJobs;
|
|
40
|
+
//# sourceMappingURL=jobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../../src/testing/jobs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACrB,MAAM,sBAAsB,CAAA;AAE7B,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,iBAAiB,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAAE,GAAG,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,CAAA;AAEpD,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAA;AAE9C,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,qBAAa,aAAc,SAAQ,KAAK;IAIpC,QAAQ,CAAC,MAAM,EAAE,YAAY;IAC7B,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,EAAE;IAJxC,SAAkB,IAAI,mBAAkB;gBAG7B,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,iBAAiB,EAAE;CAMzC;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IAGrC,QAAQ,CAAC,MAAM,EAAE,YAAY;IAFzC,SAAkB,IAAI,8BAA6B;gBAE9B,MAAM,EAAE,YAAY;CAK1C;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACxD,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAClE,OAAO,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,OAAO,EAAE,CAAC,CAAA;IAC5D,OAAO,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,OAAO,EAAE,CAAC,CAAA;IAC5D,MAAM,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,OAAO,EAAE,CAAC,CAAA;CAC5D,CAAA;AAMD,wBAAgB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,QAAQ,CAoErE"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export class TestJobsError extends Error {
|
|
2
|
+
report;
|
|
3
|
+
failures;
|
|
4
|
+
name = 'TestJobsError';
|
|
5
|
+
constructor(report, failures) {
|
|
6
|
+
super(`[bunderstack] ${failures.length} background job${failures.length === 1 ? '' : 's'} failed: ${failures.map((failure) => `${failure.name}: ${failure.lastError ?? 'unknown error'}`).join('; ')}`);
|
|
7
|
+
this.report = report;
|
|
8
|
+
this.failures = failures;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class TestJobsConvergenceError extends Error {
|
|
12
|
+
report;
|
|
13
|
+
name = 'TestJobsConvergenceError';
|
|
14
|
+
constructor(report) {
|
|
15
|
+
super(`[bunderstack] background jobs did not become idle after ${report.ticks} ticks (${report.remainingRunnable} still runnable)`);
|
|
16
|
+
this.report = report;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function timestamp(value) {
|
|
20
|
+
return value === undefined ? Date.now() : new Date(value).getTime();
|
|
21
|
+
}
|
|
22
|
+
export function createTestJobs(handle) {
|
|
23
|
+
const list = async (filter = {}, status) => {
|
|
24
|
+
const { jobs } = await handle.inspect(Date.now());
|
|
25
|
+
return Object.freeze(jobs.filter((job) => (!status || job.status === status) &&
|
|
26
|
+
(!filter.name || job.name === filter.name) &&
|
|
27
|
+
(!filter.dedupeKey || job.dedupeKey === filter.dedupeKey)));
|
|
28
|
+
};
|
|
29
|
+
return {
|
|
30
|
+
inspect: (filter) => list(filter),
|
|
31
|
+
pending: (filter) => list(filter, 'pending'),
|
|
32
|
+
failed: (filter) => list(filter, 'failed'),
|
|
33
|
+
async runNext(options = {}) {
|
|
34
|
+
const now = timestamp(options.now);
|
|
35
|
+
const tick = await handle.tick(now);
|
|
36
|
+
const inspection = await handle.inspect(now);
|
|
37
|
+
return {
|
|
38
|
+
ticks: 1,
|
|
39
|
+
...tick,
|
|
40
|
+
remainingRunnable: inspection.runnable,
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
async runUntilIdle(options = {}) {
|
|
44
|
+
const now = timestamp(options.now);
|
|
45
|
+
const maxTicks = options.maxTicks ?? 100;
|
|
46
|
+
if (!Number.isInteger(maxTicks) || maxTicks <= 0) {
|
|
47
|
+
throw new TypeError('[bunderstack] maxTicks must be a positive integer');
|
|
48
|
+
}
|
|
49
|
+
const report = {
|
|
50
|
+
ticks: 0,
|
|
51
|
+
claimed: 0,
|
|
52
|
+
ran: 0,
|
|
53
|
+
failed: 0,
|
|
54
|
+
remainingRunnable: 0,
|
|
55
|
+
};
|
|
56
|
+
let inspection;
|
|
57
|
+
do {
|
|
58
|
+
const tick = await handle.tick(now);
|
|
59
|
+
report.ticks++;
|
|
60
|
+
report.claimed += tick.claimed;
|
|
61
|
+
report.ran += tick.ran;
|
|
62
|
+
report.failed += tick.failed;
|
|
63
|
+
inspection = await handle.inspect(now);
|
|
64
|
+
report.remainingRunnable = inspection.runnable;
|
|
65
|
+
if (inspection.runnable > 0 && report.ticks >= maxTicks) {
|
|
66
|
+
throw new TestJobsConvergenceError(report);
|
|
67
|
+
}
|
|
68
|
+
} while (inspection.runnable > 0);
|
|
69
|
+
if ((options.failOnJobError ?? true) && inspection.failed.length > 0) {
|
|
70
|
+
throw new TestJobsError(report, inspection.failed);
|
|
71
|
+
}
|
|
72
|
+
return report;
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=jobs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jobs.js","sourceRoot":"","sources":["../../src/testing/jobs.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RuntimeJobFailure,\n RuntimeTestJob,\n RuntimeTestingHandle,\n} from '../backend-internals'\n\nexport type JobRunReport = {\n ticks: number\n claimed: number\n ran: number\n failed: number\n remainingRunnable: number\n}\n\nexport type RunNextOptions = { now?: Date | number }\n\nexport type RunUntilIdleOptions = RunNextOptions & {\n maxTicks?: number\n failOnJobError?: boolean\n}\n\nexport type TestJob = Readonly<RuntimeTestJob>\n\nexport type TestJobFilter = {\n name?: string\n dedupeKey?: string\n}\n\nexport class TestJobsError extends Error {\n override readonly name = 'TestJobsError'\n\n constructor(\n readonly report: JobRunReport,\n readonly failures: RuntimeJobFailure[],\n ) {\n super(\n `[bunderstack] ${failures.length} background job${failures.length === 1 ? '' : 's'} failed: ${failures.map((failure) => `${failure.name}: ${failure.lastError ?? 'unknown error'}`).join('; ')}`,\n )\n }\n}\n\nexport class TestJobsConvergenceError extends Error {\n override readonly name = 'TestJobsConvergenceError'\n\n constructor(readonly report: JobRunReport) {\n super(\n `[bunderstack] background jobs did not become idle after ${report.ticks} ticks (${report.remainingRunnable} still runnable)`,\n )\n }\n}\n\nexport type TestJobs = {\n runNext(options?: RunNextOptions): Promise<JobRunReport>\n runUntilIdle(options?: RunUntilIdleOptions): Promise<JobRunReport>\n inspect(filter?: TestJobFilter): Promise<readonly TestJob[]>\n pending(filter?: TestJobFilter): Promise<readonly TestJob[]>\n failed(filter?: TestJobFilter): Promise<readonly TestJob[]>\n}\n\nfunction timestamp(value: Date | number | undefined): number {\n return value === undefined ? Date.now() : new Date(value).getTime()\n}\n\nexport function createTestJobs(handle: RuntimeTestingHandle): TestJobs {\n const list = async (\n filter: TestJobFilter = {},\n status?: TestJob['status'],\n ) => {\n const { jobs } = await handle.inspect(Date.now())\n return Object.freeze(\n jobs.filter(\n (job) =>\n (!status || job.status === status) &&\n (!filter.name || job.name === filter.name) &&\n (!filter.dedupeKey || job.dedupeKey === filter.dedupeKey),\n ),\n )\n }\n\n return {\n inspect: (filter) => list(filter),\n pending: (filter) => list(filter, 'pending'),\n failed: (filter) => list(filter, 'failed'),\n\n async runNext(options = {}) {\n const now = timestamp(options.now)\n const tick = await handle.tick(now)\n const inspection = await handle.inspect(now)\n return {\n ticks: 1,\n ...tick,\n remainingRunnable: inspection.runnable,\n }\n },\n\n async runUntilIdle(options = {}) {\n const now = timestamp(options.now)\n const maxTicks = options.maxTicks ?? 100\n if (!Number.isInteger(maxTicks) || maxTicks <= 0) {\n throw new TypeError('[bunderstack] maxTicks must be a positive integer')\n }\n\n const report: JobRunReport = {\n ticks: 0,\n claimed: 0,\n ran: 0,\n failed: 0,\n remainingRunnable: 0,\n }\n let inspection: Awaited<ReturnType<RuntimeTestingHandle['inspect']>>\n\n do {\n const tick = await handle.tick(now)\n report.ticks++\n report.claimed += tick.claimed\n report.ran += tick.ran\n report.failed += tick.failed\n inspection = await handle.inspect(now)\n report.remainingRunnable = inspection.runnable\n\n if (inspection.runnable > 0 && report.ticks >= maxTicks) {\n throw new TestJobsConvergenceError(report)\n }\n } while (inspection.runnable > 0)\n\n if ((options.failOnJobError ?? true) && inspection.failed.length > 0) {\n throw new TestJobsError(report, inspection.failed)\n }\n return report\n },\n }\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BunderstackLogger, BunderstackLogLevel } from '../logging.js';
|
|
2
|
+
export type TestLogMode = 'capture' | 'inherit' | 'silent';
|
|
3
|
+
export type TestLogEntry = {
|
|
4
|
+
readonly level: BunderstackLogLevel;
|
|
5
|
+
readonly message: string;
|
|
6
|
+
readonly args: readonly unknown[];
|
|
7
|
+
};
|
|
8
|
+
export type TestLogs = {
|
|
9
|
+
readonly entries: readonly Readonly<TestLogEntry>[];
|
|
10
|
+
readonly errors: readonly Readonly<TestLogEntry>[];
|
|
11
|
+
readonly warnings: readonly Readonly<TestLogEntry>[];
|
|
12
|
+
clear(): void;
|
|
13
|
+
};
|
|
14
|
+
export declare function createTestLogs(mode?: TestLogMode): {
|
|
15
|
+
logger: BunderstackLogger;
|
|
16
|
+
logs: TestLogs;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=logs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/testing/logs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAExE,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;AAE1D,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAA;IACnD,QAAQ,CAAC,MAAM,EAAE,SAAS,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAA;IAClD,QAAQ,CAAC,QAAQ,EAAE,SAAS,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAA;IACpD,KAAK,IAAI,IAAI,CAAA;CACd,CAAA;AAcD,wBAAgB,cAAc,CAAC,IAAI,GAAE,WAAuB,GAAG;IAC7D,MAAM,EAAE,iBAAiB,CAAA;IACzB,IAAI,EAAE,QAAQ,CAAA;CACf,CAuCA"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
function render(value) {
|
|
2
|
+
if (value instanceof Error)
|
|
3
|
+
return `${value.name}: ${value.message}`;
|
|
4
|
+
if (typeof value === 'string')
|
|
5
|
+
return value;
|
|
6
|
+
if (value === null)
|
|
7
|
+
return 'null';
|
|
8
|
+
if (value === undefined)
|
|
9
|
+
return 'undefined';
|
|
10
|
+
try {
|
|
11
|
+
return JSON.stringify(value);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return String(value);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function createTestLogs(mode = 'capture') {
|
|
18
|
+
const entries = [];
|
|
19
|
+
const write = (level, args) => {
|
|
20
|
+
if (mode !== 'silent') {
|
|
21
|
+
entries.push(Object.freeze({
|
|
22
|
+
level,
|
|
23
|
+
message: args.map(render).join(' '),
|
|
24
|
+
args: Object.freeze([...args]),
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
if (mode === 'inherit')
|
|
28
|
+
console[level](...args);
|
|
29
|
+
};
|
|
30
|
+
const snapshot = (level) => Object.freeze(entries.filter((entry) => !level || entry.level === level).slice());
|
|
31
|
+
return {
|
|
32
|
+
logger: {
|
|
33
|
+
info: (...args) => write('info', args),
|
|
34
|
+
warn: (...args) => write('warn', args),
|
|
35
|
+
error: (...args) => write('error', args),
|
|
36
|
+
},
|
|
37
|
+
logs: {
|
|
38
|
+
get entries() {
|
|
39
|
+
return snapshot();
|
|
40
|
+
},
|
|
41
|
+
get errors() {
|
|
42
|
+
return snapshot('error');
|
|
43
|
+
},
|
|
44
|
+
get warnings() {
|
|
45
|
+
return snapshot('warn');
|
|
46
|
+
},
|
|
47
|
+
clear() {
|
|
48
|
+
entries.length = 0;
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=logs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/testing/logs.ts"],"names":[],"mappings":"AAiBA,SAAS,MAAM,CAAC,KAAc;IAC5B,IAAI,KAAK,YAAY,KAAK;QAAE,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAA;IACpE,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC3C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAA;IACjC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,WAAW,CAAA;IAC3C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAoB,SAAS;IAI1D,MAAM,OAAO,GAAmB,EAAE,CAAA;IAClC,MAAM,KAAK,GAAG,CAAC,KAA0B,EAAE,IAAe,EAAE,EAAE;QAC5D,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CACV,MAAM,CAAC,MAAM,CAAC;gBACZ,KAAK;gBACL,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;gBACnC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;aAC/B,CAAC,CACH,CAAA;QACH,CAAC;QACD,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IACjD,CAAC,CAAA;IACD,MAAM,QAAQ,GAAG,CAAC,KAA2B,EAAE,EAAE,CAC/C,MAAM,CAAC,MAAM,CACX,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,KAAK,EAAE,CACnE,CAAA;IACH,OAAO;QACL,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC;YACtC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC;YACtC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC;SACzC;QACD,IAAI,EAAE;YACJ,IAAI,OAAO;gBACT,OAAO,QAAQ,EAAE,CAAA;YACnB,CAAC;YACD,IAAI,MAAM;gBACR,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAA;YAC1B,CAAC;YACD,IAAI,QAAQ;gBACV,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAA;YACzB,CAAC;YACD,KAAK;gBACH,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA;YACpB,CAAC;SACF;KACF,CAAA;AACH,CAAC","sourcesContent":["import type { BunderstackLogger, BunderstackLogLevel } from '../logging'\n\nexport type TestLogMode = 'capture' | 'inherit' | 'silent'\n\nexport type TestLogEntry = {\n readonly level: BunderstackLogLevel\n readonly message: string\n readonly args: readonly unknown[]\n}\n\nexport type TestLogs = {\n readonly entries: readonly Readonly<TestLogEntry>[]\n readonly errors: readonly Readonly<TestLogEntry>[]\n readonly warnings: readonly Readonly<TestLogEntry>[]\n clear(): void\n}\n\nfunction render(value: unknown): string {\n if (value instanceof Error) return `${value.name}: ${value.message}`\n if (typeof value === 'string') return value\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n try {\n return JSON.stringify(value)\n } catch {\n return String(value)\n }\n}\n\nexport function createTestLogs(mode: TestLogMode = 'capture'): {\n logger: BunderstackLogger\n logs: TestLogs\n} {\n const entries: TestLogEntry[] = []\n const write = (level: BunderstackLogLevel, args: unknown[]) => {\n if (mode !== 'silent') {\n entries.push(\n Object.freeze({\n level,\n message: args.map(render).join(' '),\n args: Object.freeze([...args]),\n }),\n )\n }\n if (mode === 'inherit') console[level](...args)\n }\n const snapshot = (level?: BunderstackLogLevel) =>\n Object.freeze(\n entries.filter((entry) => !level || entry.level === level).slice(),\n )\n return {\n logger: {\n info: (...args) => write('info', args),\n warn: (...args) => write('warn', args),\n error: (...args) => write('error', args),\n },\n logs: {\n get entries() {\n return snapshot()\n },\n get errors() {\n return snapshot('error')\n },\n get warnings() {\n return snapshot('warn')\n },\n clear() {\n entries.length = 0\n },\n },\n }\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ResolvedStorageBuckets, StorageConfigInput } from '../storage/buckets.js';
|
|
2
|
+
export type TestStorage = {
|
|
3
|
+
read(key: string): Promise<Uint8Array>;
|
|
4
|
+
};
|
|
5
|
+
export declare function resolveTestBuckets(input: StorageConfigInput | undefined, root: string): ResolvedStorageBuckets;
|
|
6
|
+
export declare function createTestStorage(resolved: ResolvedStorageBuckets): TestStorage;
|
|
7
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/testing/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,oBAAoB,CAAA;AAK3B,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;CACvC,CAAA;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,kBAAkB,GAAG,SAAS,EACrC,IAAI,EAAE,MAAM,GACX,sBAAsB,CAWxB;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,sBAAsB,GAC/B,WAAW,CAcb"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { resolveBuckets } from '../storage/buckets.js';
|
|
2
|
+
import { createBucketStorages } from '../storage/registry.js';
|
|
3
|
+
export function resolveTestBuckets(input, root) {
|
|
4
|
+
const resolved = resolveBuckets(input, {});
|
|
5
|
+
return {
|
|
6
|
+
defaultBucket: resolved.defaultBucket,
|
|
7
|
+
buckets: new Map([...resolved.buckets].map(([name, bucket]) => [
|
|
8
|
+
name,
|
|
9
|
+
{ ...bucket, backend: { type: 'local', path: root } },
|
|
10
|
+
])),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function createTestStorage(resolved) {
|
|
14
|
+
const registry = createBucketStorages(resolved);
|
|
15
|
+
return {
|
|
16
|
+
async read(key) {
|
|
17
|
+
const bucketName = key.split('/')[0] || resolved.defaultBucket;
|
|
18
|
+
const adapter = registry.get(bucketName)?.adapter;
|
|
19
|
+
if (!adapter)
|
|
20
|
+
throw new Error(`Unknown bucket: ${bucketName}`);
|
|
21
|
+
const response = await adapter.get(key);
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
throw new Error(`Storage object not found: ${key}`);
|
|
24
|
+
}
|
|
25
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/testing/storage.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAM1D,MAAM,UAAU,kBAAkB,CAChC,KAAqC,EACrC,IAAY;IAEZ,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAC1C,OAAO;QACL,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,OAAO,EAAE,IAAI,GAAG,CACd,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;YAC5C,IAAI;YACJ,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;SAC/D,CAAC,CACH;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,QAAgC;IAEhC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAA;IAC/C,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,GAAG;YACZ,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,aAAa,CAAA;YAC9D,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,OAAO,CAAA;YACjD,IAAI,CAAC,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,UAAU,EAAE,CAAC,CAAA;YAC9D,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACvC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAA;YACrD,CAAC;YACD,OAAO,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAA;QACrD,CAAC;KACF,CAAA;AACH,CAAC","sourcesContent":["import type {\n ResolvedStorageBuckets,\n StorageConfigInput,\n} from '../storage/buckets'\n\nimport { resolveBuckets } from '../storage/buckets'\nimport { createBucketStorages } from '../storage/registry'\n\nexport type TestStorage = {\n read(key: string): Promise<Uint8Array>\n}\n\nexport function resolveTestBuckets(\n input: StorageConfigInput | undefined,\n root: string,\n): ResolvedStorageBuckets {\n const resolved = resolveBuckets(input, {})\n return {\n defaultBucket: resolved.defaultBucket,\n buckets: new Map(\n [...resolved.buckets].map(([name, bucket]) => [\n name,\n { ...bucket, backend: { type: 'local' as const, path: root } },\n ]),\n ),\n }\n}\n\nexport function createTestStorage(\n resolved: ResolvedStorageBuckets,\n): TestStorage {\n const registry = createBucketStorages(resolved)\n return {\n async read(key) {\n const bucketName = key.split('/')[0] || resolved.defaultBucket\n const adapter = registry.get(bucketName)?.adapter\n if (!adapter) throw new Error(`Unknown bucket: ${bucketName}`)\n const response = await adapter.get(key)\n if (!response.ok) {\n throw new Error(`Storage object not found: ${key}`)\n }\n return new Uint8Array(await response.arrayBuffer())\n },\n }\n}\n"]}
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,27 +1,11 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
};
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* Mock the auth session resolver on a Bunderstack app instance for unit testing.
|
|
13
|
-
*/
|
|
14
|
-
export declare function mockAuthSession<TUser extends {
|
|
15
|
-
id: string;
|
|
16
|
-
email: string;
|
|
17
|
-
name?: string;
|
|
18
|
-
role?: string;
|
|
19
|
-
}>(app: BunderstackAppLike, resolver: (opts: {
|
|
20
|
-
headers: Headers;
|
|
21
|
-
}) => Promise<{
|
|
22
|
-
user: TUser;
|
|
23
|
-
session?: {
|
|
24
|
-
activeOrganizationId?: string | null;
|
|
25
|
-
} | null;
|
|
26
|
-
} | null>): void;
|
|
1
|
+
export { configureTestApp, createTestApp } from './testing/fixture.js';
|
|
2
|
+
export type { ConfiguredTestFixture, TestCleanup, TestConfigureOptions, TestFactory, TestFixture, TestMethod, TestOptions, TestSetup, } from './testing/fixture.js';
|
|
3
|
+
export { mockAuthSession, TestAuthError } from './testing/auth.js';
|
|
4
|
+
export type { SignInEmailInput, SignUpEmailInput, TestAuth, TestIdentity, TestSession, TestUser, } from './testing/auth.js';
|
|
5
|
+
export type { CapturedEmail, TestEmail } from './testing/email.js';
|
|
6
|
+
export type { TestStorage } from './testing/storage.js';
|
|
7
|
+
export type { TestLogEntry, TestLogMode, TestLogs } from './testing/logs.js';
|
|
8
|
+
export { TestJobsConvergenceError, TestJobsError } from './testing/jobs.js';
|
|
9
|
+
export type { JobRunReport, RunNextOptions, RunUntilIdleOptions, TestJob, TestJobFilter, TestJobs, } from './testing/jobs.js';
|
|
10
|
+
export type { TestDatabaseStrategy, TestDatabaseTarget, TestDatabaseTargetOptions, } from './database/adapter.js';
|
|
27
11
|
//# sourceMappingURL=testing.d.ts.map
|
package/dist/testing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACnE,YAAY,EACV,qBAAqB,EACrB,WAAW,EACX,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,UAAU,EACV,WAAW,EACX,SAAS,GACV,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC/D,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,QAAQ,GACT,MAAM,gBAAgB,CAAA;AACvB,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC/D,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzE,OAAO,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACxE,YAAY,EACV,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,OAAO,EACP,aAAa,EACb,QAAQ,GACT,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAA"}
|
package/dist/testing.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
// src/testing.ts — test utilities for Bunderstack applications.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export function mockAuthSession(app, resolver) {
|
|
6
|
-
const auth = app.auth;
|
|
7
|
-
if (auth?.api) {
|
|
8
|
-
auth.api.getSession = resolver;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
2
|
+
export { configureTestApp, createTestApp } from './testing/fixture.js';
|
|
3
|
+
export { mockAuthSession, TestAuthError } from './testing/auth.js';
|
|
4
|
+
export { TestJobsConvergenceError, TestJobsError } from './testing/jobs.js';
|
|
11
5
|
//# sourceMappingURL=testing.js.map
|
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,gEAAgE;
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAEhE,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAWnE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAY/D,OAAO,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA","sourcesContent":["// src/testing.ts — test utilities for Bunderstack applications.\n\nexport { configureTestApp, createTestApp } from './testing/fixture'\nexport type {\n ConfiguredTestFixture,\n TestCleanup,\n TestConfigureOptions,\n TestFactory,\n TestFixture,\n TestMethod,\n TestOptions,\n TestSetup,\n} from './testing/fixture'\nexport { mockAuthSession, TestAuthError } from './testing/auth'\nexport type {\n SignInEmailInput,\n SignUpEmailInput,\n TestAuth,\n TestIdentity,\n TestSession,\n TestUser,\n} from './testing/auth'\nexport type { CapturedEmail, TestEmail } from './testing/email'\nexport type { TestStorage } from './testing/storage'\nexport type { TestLogEntry, TestLogMode, TestLogs } from './testing/logs'\nexport { TestJobsConvergenceError, TestJobsError } from './testing/jobs'\nexport type {\n JobRunReport,\n RunNextOptions,\n RunUntilIdleOptions,\n TestJob,\n TestJobFilter,\n TestJobs,\n} from './testing/jobs'\nexport type {\n TestDatabaseStrategy,\n TestDatabaseTarget,\n TestDatabaseTargetOptions,\n} from './database/adapter'\n"]}
|
package/llms.txt
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
BUNDERSTACK
|
|
2
2
|
|
|
3
|
-
A batteries-included backend framework for Bun. Version 0.
|
|
3
|
+
A batteries-included backend framework for Bun. Version 0.22.1.
|
|
4
4
|
Docs: https://bunderstack.kcrz.dev/docs
|
|
5
5
|
This file is written for coding agents. It is dense on purpose.
|
|
6
6
|
|
|
7
7
|
WHAT IT IS
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
bunderstack() takes a Drizzle schema and returns a synchronous, side-effect-free
|
|
10
|
+
backend declaration. backend.start() materializes the production runtime whose
|
|
11
|
+
handler is a single Web-Standard Request -> Response function. backend.test()
|
|
12
|
+
materializes an isolated, lexically owned test fixture. From the schema the
|
|
13
|
+
runtime generates secured CRUD procedures. Your own procedures, file storage,
|
|
14
|
+
realtime subscriptions, and a health check live in the same oRPC graph,
|
|
15
|
+
reachable both as typed RPC and as ordinary HTTP.
|
|
14
16
|
|
|
15
17
|
Stack: Bun, Drizzle (+ drizzle-kit), Better Auth, oRPC v2, libSQL or Postgres,
|
|
16
18
|
Bun.Image. Validation accepts any Standard Schema library; generated schemas use
|
|
@@ -22,19 +24,22 @@ integration).
|
|
|
22
24
|
|
|
23
25
|
MINIMAL APP
|
|
24
26
|
|
|
25
|
-
import {
|
|
26
|
-
import { libsql } from 'bunderstack/
|
|
27
|
+
import { bunderstack } from 'bunderstack'
|
|
28
|
+
import { libsql } from 'bunderstack/libsql'
|
|
27
29
|
import * as schema from './schema'
|
|
28
30
|
|
|
29
|
-
export const
|
|
31
|
+
export const backend = bunderstack({
|
|
30
32
|
schema,
|
|
31
33
|
database: { adapter: libsql(), url: 'file:./data.db' },
|
|
32
34
|
access: { posts: { list: 'public', get: 'public' } },
|
|
33
35
|
})
|
|
34
36
|
|
|
35
|
-
export type App = typeof
|
|
37
|
+
export type App = Awaited<ReturnType<typeof backend.start>>
|
|
38
|
+
export const app = await backend.start()
|
|
39
|
+
|
|
36
40
|
Bun.serve({ fetch: app.handler })
|
|
37
41
|
|
|
42
|
+
The blueprint imports the backend declaration and never starts the runtime.
|
|
38
43
|
Database adapters are imported from their own entry points: libsql(),
|
|
39
44
|
pglite(), bunSql(), postgresJs(). Provisioning: `await provision(app)` pushes
|
|
40
45
|
the schema in development and applies committed migrations once a migrations/
|
|
@@ -71,13 +76,45 @@ Router modules are plain objects that import the base they need:
|
|
|
71
76
|
export const api = { boards: boardsRouter }
|
|
72
77
|
|
|
73
78
|
// config
|
|
74
|
-
|
|
79
|
+
bunderstack({ schema, database, api })
|
|
75
80
|
|
|
76
81
|
Do NOT write a factory that receives a bag of procedures. That pattern exists
|
|
77
82
|
only because the api option used to be a callback. The callback form still
|
|
78
83
|
works — api: (o) => ({ ... }) — for a router that must be built from the
|
|
79
84
|
framework builder at configuration time, but the object form is the default.
|
|
80
85
|
|
|
86
|
+
TESTING
|
|
87
|
+
|
|
88
|
+
Use lexical fixture ownership; do not use a process-wide app registry or a
|
|
89
|
+
global afterEach hook:
|
|
90
|
+
|
|
91
|
+
export const createFixture = backend.test.configure({
|
|
92
|
+
database: { schema: 'push' },
|
|
93
|
+
setup: async (t) => {
|
|
94
|
+
const identity = t.auth.mockSession({
|
|
95
|
+
id: 'user-1', email: 'dev@example.com', name: 'Developer',
|
|
96
|
+
})
|
|
97
|
+
return { identity, client: t.client(identity) }
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
import { backend } from './backend'
|
|
102
|
+
|
|
103
|
+
test('creates a post', async () => {
|
|
104
|
+
await using t = await createFixture()
|
|
105
|
+
const { client, identity } = t.context
|
|
106
|
+
await client.posts.create({ title: 'Hello', userId: identity.user.id })
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
The fixture owns isolated database, email, storage, realtime, and job state.
|
|
110
|
+
fixture.defer() registers LIFO async cleanup. fixture.logs captures internal
|
|
111
|
+
runtime logs by default. Auth supports sign-up, sign-in, session lookup, sign-out,
|
|
112
|
+
email verification, and multiple header-scoped mock identities. t.jobs.runNext()
|
|
113
|
+
claims one snapshot of runnable jobs. t.jobs.runUntilIdle() repeats snapshots
|
|
114
|
+
until the queue converges, a terminal job fails, or its limits are reached; it
|
|
115
|
+
does not advance the clock to delayed jobs automatically. inspect(), pending(),
|
|
116
|
+
and failed() expose queue rows for assertions.
|
|
117
|
+
|
|
81
118
|
BASES
|
|
82
119
|
|
|
83
120
|
o.public session resolved only if the handler calls context.getSession()
|
|
@@ -118,7 +155,7 @@ Two placements, and the difference is the thing people get wrong.
|
|
|
118
155
|
.use() on a base reaches only procedures built from that base. Use it for
|
|
119
156
|
rules about a group of procedures: role checks, organization scope, quotas.
|
|
120
157
|
|
|
121
|
-
middleware: [...] in
|
|
158
|
+
middleware: [...] in bunderstack reaches EVERY procedure, including the
|
|
122
159
|
generated CRUD, storage, realtime, and health. Use it for observability. A
|
|
123
160
|
tracing middleware attached to a base leaves generated CRUD unmeasured,
|
|
124
161
|
because the framework builds those procedures itself and they never pass
|
|
@@ -137,7 +174,7 @@ through an application base.
|
|
|
137
174
|
}
|
|
138
175
|
})
|
|
139
176
|
|
|
140
|
-
|
|
177
|
+
bunderstack({ schema, database, middleware: [instrumentation], api })
|
|
141
178
|
|
|
142
179
|
Rules for graph-wide middleware:
|
|
143
180
|
- It runs before authentication. context.user does not exist there.
|
|
@@ -262,7 +299,7 @@ ENV
|
|
|
262
299
|
|
|
263
300
|
Server variables must not start with PUBLIC_; client variables must. Validated
|
|
264
301
|
at boot; app.env and context.env are typed from the schema. Declare the schema
|
|
265
|
-
in its own module so both
|
|
302
|
+
in its own module so both bunderstack and defineApi can use it.
|
|
266
303
|
|
|
267
304
|
AUTH
|
|
268
305
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunderstack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.1",
|
|
4
4
|
"description": "Batteries-included backend framework for Bun: type-safe oRPC APIs, auth, storage, realtime, jobs, email, and validated env from one config.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"backend",
|
|
@@ -48,19 +48,23 @@
|
|
|
48
48
|
"types": "./dist/codegen.d.ts",
|
|
49
49
|
"default": "./dist/codegen.js"
|
|
50
50
|
},
|
|
51
|
-
"./
|
|
51
|
+
"./bun-sql": {
|
|
52
52
|
"types": "./dist/database/bun-sql.d.ts",
|
|
53
53
|
"default": "./dist/database/bun-sql.js"
|
|
54
54
|
},
|
|
55
|
-
"./
|
|
55
|
+
"./bun-sqlite": {
|
|
56
|
+
"types": "./dist/database/bun-sqlite.d.ts",
|
|
57
|
+
"default": "./dist/database/bun-sqlite.js"
|
|
58
|
+
},
|
|
59
|
+
"./libsql": {
|
|
56
60
|
"types": "./dist/database/libsql.d.ts",
|
|
57
61
|
"default": "./dist/database/libsql.js"
|
|
58
62
|
},
|
|
59
|
-
"./
|
|
63
|
+
"./pglite": {
|
|
60
64
|
"types": "./dist/database/pglite.d.ts",
|
|
61
65
|
"default": "./dist/database/pglite.js"
|
|
62
66
|
},
|
|
63
|
-
"./
|
|
67
|
+
"./postgres-js": {
|
|
64
68
|
"types": "./dist/database/postgres-js.d.ts",
|
|
65
69
|
"default": "./dist/database/postgres-js.js"
|
|
66
70
|
},
|
|
@@ -72,11 +76,15 @@
|
|
|
72
76
|
"types": "./dist/provision.d.ts",
|
|
73
77
|
"default": "./dist/provision.js"
|
|
74
78
|
},
|
|
79
|
+
"./testing": {
|
|
80
|
+
"types": "./dist/testing.d.ts",
|
|
81
|
+
"default": "./dist/testing.js"
|
|
82
|
+
},
|
|
75
83
|
"./schema": {
|
|
76
84
|
"types": "./dist/schema-export.d.ts",
|
|
77
85
|
"default": "./dist/schema-export.js"
|
|
78
86
|
},
|
|
79
|
-
"./schema
|
|
87
|
+
"./schema-pg": {
|
|
80
88
|
"types": "./dist/schema-export-pg.d.ts",
|
|
81
89
|
"default": "./dist/schema-export-pg.js"
|
|
82
90
|
},
|
|
@@ -84,7 +92,7 @@
|
|
|
84
92
|
"types": "./dist/typeid.d.ts",
|
|
85
93
|
"default": "./dist/typeid.js"
|
|
86
94
|
},
|
|
87
|
-
"./typeid
|
|
95
|
+
"./typeid-pg": {
|
|
88
96
|
"types": "./dist/typeid-pg.d.ts",
|
|
89
97
|
"default": "./dist/typeid-pg.js"
|
|
90
98
|
},
|
|
@@ -100,7 +108,7 @@
|
|
|
100
108
|
"types": "./dist/cron.d.ts",
|
|
101
109
|
"default": "./dist/cron.js"
|
|
102
110
|
},
|
|
103
|
-
"./email
|
|
111
|
+
"./email-smtp": {
|
|
104
112
|
"types": "./dist/email/smtp.d.ts",
|
|
105
113
|
"default": "./dist/email/smtp.js"
|
|
106
114
|
},
|
|
@@ -112,23 +120,23 @@
|
|
|
112
120
|
"types": "./dist/client/index.d.ts",
|
|
113
121
|
"default": "./dist/client/index.js"
|
|
114
122
|
},
|
|
115
|
-
"./client
|
|
123
|
+
"./client-rest": {
|
|
116
124
|
"types": "./dist/client/rest.d.ts",
|
|
117
125
|
"default": "./dist/client/rest.js"
|
|
118
126
|
},
|
|
119
|
-
"./client
|
|
127
|
+
"./client-react": {
|
|
120
128
|
"types": "./dist/client/react.d.ts",
|
|
121
129
|
"default": "./dist/client/react.js"
|
|
122
130
|
},
|
|
123
|
-
"./client
|
|
131
|
+
"./client-solid": {
|
|
124
132
|
"types": "./dist/client/solid.d.ts",
|
|
125
133
|
"default": "./dist/client/solid.js"
|
|
126
134
|
},
|
|
127
|
-
"./client
|
|
135
|
+
"./client-svelte": {
|
|
128
136
|
"types": "./dist/client/svelte.d.ts",
|
|
129
137
|
"default": "./dist/client/svelte.js"
|
|
130
138
|
},
|
|
131
|
-
"./client
|
|
139
|
+
"./client-vue": {
|
|
132
140
|
"types": "./dist/client/vue.d.ts",
|
|
133
141
|
"default": "./dist/client/vue.js"
|
|
134
142
|
},
|
|
@@ -136,7 +144,7 @@
|
|
|
136
144
|
"types": "./dist/query/index.d.ts",
|
|
137
145
|
"default": "./dist/query/index.js"
|
|
138
146
|
},
|
|
139
|
-
"./query
|
|
147
|
+
"./query-react": {
|
|
140
148
|
"types": "./dist/query/react.d.ts",
|
|
141
149
|
"default": "./dist/query/react.js"
|
|
142
150
|
},
|
|
@@ -148,7 +156,7 @@
|
|
|
148
156
|
"types": "./dist/start/index.d.ts",
|
|
149
157
|
"default": "./dist/start/index.js"
|
|
150
158
|
},
|
|
151
|
-
"./start
|
|
159
|
+
"./start-auth": {
|
|
152
160
|
"types": "./dist/start/auth-client.d.ts",
|
|
153
161
|
"default": "./dist/start/auth-client.js"
|
|
154
162
|
}
|