@cimplify/sdk 0.82.0 → 0.83.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.
- package/dist/{chunk-SRJEMEVZ.js → chunk-FKBXZ2A6.js} +212 -6
- package/dist/{chunk-7PAQR3VC.mjs → chunk-I6RE4BKH.mjs} +4 -2
- package/dist/{chunk-IZDJEDR4.js → chunk-ODEPW244.js} +5 -3
- package/dist/{chunk-BRVIXGUW.mjs → chunk-PLTP6HWW.mjs} +212 -6
- package/dist/{client-BSpVgule.d.mts → client-Cogz7C1t.d.mts} +1 -1
- package/dist/{client-Dh-KIIX8.d.ts → client-Cq3B-WXv.d.ts} +1 -1
- package/dist/mock/cli.mjs +309 -19
- package/dist/mock/library.js +223 -6
- package/dist/mock/library.mjs +216 -7
- package/dist/mock/msw.js +212 -6
- package/dist/mock/msw.mjs +212 -6
- package/dist/{server-tr993CPj.d.mts → server-DaovvB9J.d.mts} +86 -2
- package/dist/{server-wAB-qfyZ.d.ts → server-ZGCyuz4V.d.ts} +86 -2
- package/dist/testing/msw.d.mts +1 -1
- package/dist/testing/msw.d.ts +1 -1
- package/dist/testing/msw.js +2 -2
- package/dist/testing/msw.mjs +1 -1
- package/dist/testing/suite.d.mts +3 -3
- package/dist/testing/suite.d.ts +3 -3
- package/dist/testing/suite.js +21 -21
- package/dist/testing/suite.mjs +2 -2
- package/dist/testing.d.mts +23 -17
- package/dist/testing.d.ts +23 -17
- package/dist/testing.js +77 -77
- package/dist/testing.mjs +3 -3
- package/package.json +1 -1
package/dist/mock/cli.mjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { writeFileSync, existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { basename, isAbsolute, resolve } from 'path';
|
|
4
|
+
import { pathToFileURL } from 'url';
|
|
2
5
|
import { createServer } from 'http';
|
|
3
6
|
import { Http2ServerRequest, constants } from 'http2';
|
|
4
7
|
import { Readable } from 'stream';
|
|
5
8
|
import crypto, { createHmac } from 'crypto';
|
|
6
|
-
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
7
9
|
|
|
8
10
|
var RequestError = class extends Error {
|
|
9
11
|
constructor(message, options) {
|
|
@@ -490,7 +492,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
|
490
492
|
});
|
|
491
493
|
if (!chunk) {
|
|
492
494
|
if (i === 1) {
|
|
493
|
-
await new Promise((
|
|
495
|
+
await new Promise((resolve2) => setTimeout(resolve2));
|
|
494
496
|
maxReadCount = 3;
|
|
495
497
|
continue;
|
|
496
498
|
}
|
|
@@ -6533,6 +6535,14 @@ function createLinkService({ clock, ids }) {
|
|
|
6533
6535
|
};
|
|
6534
6536
|
}
|
|
6535
6537
|
|
|
6538
|
+
// src/mock/state/snapshot.ts
|
|
6539
|
+
function applySnapshot(reg, data) {
|
|
6540
|
+
for (const [k, v] of Object.entries(data)) {
|
|
6541
|
+
const store = reg[k];
|
|
6542
|
+
if (store) store.loadJSON(v);
|
|
6543
|
+
}
|
|
6544
|
+
}
|
|
6545
|
+
|
|
6536
6546
|
// src/mock/seeds/image.ts
|
|
6537
6547
|
var CDN_BASE_URL = "https://static-tmp.cimplify.io";
|
|
6538
6548
|
function seedImage(industry, slug) {
|
|
@@ -10900,15 +10910,214 @@ function applySeed(registry, name) {
|
|
|
10900
10910
|
return fn(registry);
|
|
10901
10911
|
}
|
|
10902
10912
|
|
|
10913
|
+
// src/mock/seeds/context.ts
|
|
10914
|
+
var SEED_ISO = "2026-01-01T00:00:00.000Z";
|
|
10915
|
+
var ID_PREFIX = {
|
|
10916
|
+
business: "bus_",
|
|
10917
|
+
category: "cat_",
|
|
10918
|
+
collection: "col_",
|
|
10919
|
+
product: "prod_",
|
|
10920
|
+
service: "svc_"
|
|
10921
|
+
};
|
|
10922
|
+
var DEFAULT_CURRENCY = "GHS";
|
|
10923
|
+
function slugify(value) {
|
|
10924
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
10925
|
+
}
|
|
10926
|
+
function makeSeedContext(registry) {
|
|
10927
|
+
let current;
|
|
10928
|
+
const requireBusiness = () => {
|
|
10929
|
+
if (current) return current;
|
|
10930
|
+
const sole = registry.businesses.list();
|
|
10931
|
+
if (sole.length === 1) {
|
|
10932
|
+
current = sole[0];
|
|
10933
|
+
return current;
|
|
10934
|
+
}
|
|
10935
|
+
throw new Error("Seed must create a business (ctx.business) before adding child records.");
|
|
10936
|
+
};
|
|
10937
|
+
const resolveCategoryId = (cat) => {
|
|
10938
|
+
if (!cat) return void 0;
|
|
10939
|
+
if (typeof cat !== "string") return cat.id;
|
|
10940
|
+
if (registry.categories.get(cat)) return cat;
|
|
10941
|
+
return registry.categories.list().find((c) => c.slug === cat)?.id;
|
|
10942
|
+
};
|
|
10943
|
+
const resolveCollectionId = (col) => {
|
|
10944
|
+
if (!col) return void 0;
|
|
10945
|
+
if (typeof col !== "string") return col.id;
|
|
10946
|
+
if (registry.collections.get(col)) return col;
|
|
10947
|
+
return registry.collections.list().find((c) => c.slug === col)?.id;
|
|
10948
|
+
};
|
|
10949
|
+
return {
|
|
10950
|
+
registry,
|
|
10951
|
+
business(input) {
|
|
10952
|
+
const handle = input.handle ?? slugify(input.name);
|
|
10953
|
+
const id = `${ID_PREFIX.business}${slugify(handle)}`;
|
|
10954
|
+
const business = {
|
|
10955
|
+
business_type: "other",
|
|
10956
|
+
email: `hello@${handle}.test`,
|
|
10957
|
+
default_currency: DEFAULT_CURRENCY,
|
|
10958
|
+
default_offers_table_service: false,
|
|
10959
|
+
default_accepts_online_orders: true,
|
|
10960
|
+
status: "active",
|
|
10961
|
+
created_by: "seed",
|
|
10962
|
+
preferences: {},
|
|
10963
|
+
is_online_only: true,
|
|
10964
|
+
enabled_payment_types: ["mobile_money"],
|
|
10965
|
+
default_location_settings: {},
|
|
10966
|
+
country_code: "GH",
|
|
10967
|
+
timezone: "Africa/Accra",
|
|
10968
|
+
...input,
|
|
10969
|
+
id,
|
|
10970
|
+
handle,
|
|
10971
|
+
created_at: input.created_at ?? SEED_ISO,
|
|
10972
|
+
updated_at: input.updated_at ?? SEED_ISO
|
|
10973
|
+
};
|
|
10974
|
+
registry.businesses.put(id, business);
|
|
10975
|
+
current = business;
|
|
10976
|
+
return business;
|
|
10977
|
+
},
|
|
10978
|
+
category(input) {
|
|
10979
|
+
const business = requireBusiness();
|
|
10980
|
+
const slug = input.slug ?? slugify(input.name);
|
|
10981
|
+
const id = `${ID_PREFIX.category}${slug}`;
|
|
10982
|
+
const category = {
|
|
10983
|
+
id,
|
|
10984
|
+
business_id: business.id,
|
|
10985
|
+
name: input.name,
|
|
10986
|
+
slug,
|
|
10987
|
+
description: input.description,
|
|
10988
|
+
image: input.image,
|
|
10989
|
+
product_ids: [],
|
|
10990
|
+
display_order: input.displayOrder ?? 0,
|
|
10991
|
+
is_active: true,
|
|
10992
|
+
created_at: SEED_ISO,
|
|
10993
|
+
updated_at: SEED_ISO
|
|
10994
|
+
};
|
|
10995
|
+
registry.categories.put(id, category);
|
|
10996
|
+
return category;
|
|
10997
|
+
},
|
|
10998
|
+
collection(input) {
|
|
10999
|
+
const business = requireBusiness();
|
|
11000
|
+
const slug = input.slug ?? slugify(input.name);
|
|
11001
|
+
const id = `${ID_PREFIX.collection}${slug}`;
|
|
11002
|
+
const collection = {
|
|
11003
|
+
id,
|
|
11004
|
+
business_id: business.id,
|
|
11005
|
+
name: input.name,
|
|
11006
|
+
slug,
|
|
11007
|
+
description: input.description,
|
|
11008
|
+
product_ids: [],
|
|
11009
|
+
is_active: true,
|
|
11010
|
+
created_at: SEED_ISO,
|
|
11011
|
+
updated_at: SEED_ISO
|
|
11012
|
+
};
|
|
11013
|
+
registry.collections.put(id, collection);
|
|
11014
|
+
return collection;
|
|
11015
|
+
},
|
|
11016
|
+
product(input) {
|
|
11017
|
+
const business = requireBusiness();
|
|
11018
|
+
const slug = input.slug ?? slugify(input.name);
|
|
11019
|
+
const id = `${ID_PREFIX.product}${slug}`;
|
|
11020
|
+
const categoryId = resolveCategoryId(input.category);
|
|
11021
|
+
const collectionId = resolveCollectionId(input.collection);
|
|
11022
|
+
const product = {
|
|
11023
|
+
id,
|
|
11024
|
+
business_id: business.id,
|
|
11025
|
+
name: input.name,
|
|
11026
|
+
slug,
|
|
11027
|
+
description: input.description,
|
|
11028
|
+
product_type: input.productType ?? "product",
|
|
11029
|
+
base_price: input.price,
|
|
11030
|
+
currency: input.currency ?? business.default_currency,
|
|
11031
|
+
image: input.image,
|
|
11032
|
+
images: input.images ?? (input.image ? [input.image] : []),
|
|
11033
|
+
is_available: true,
|
|
11034
|
+
category_ids: categoryId ? [categoryId] : [],
|
|
11035
|
+
collection_ids: collectionId ? [collectionId] : [],
|
|
11036
|
+
add_on_ids: [],
|
|
11037
|
+
variant_ids: [],
|
|
11038
|
+
tags: input.tags ?? [],
|
|
11039
|
+
calories: input.calories,
|
|
11040
|
+
allergies: input.allergies ?? [],
|
|
11041
|
+
ingredients: input.ingredients ?? [],
|
|
11042
|
+
pairings: [],
|
|
11043
|
+
is_signature: input.isSignature ?? false,
|
|
11044
|
+
is_new: input.isNew ?? false,
|
|
11045
|
+
duration_minutes: input.durationMinutes,
|
|
11046
|
+
metadata: input.metadata,
|
|
11047
|
+
created_at: SEED_ISO,
|
|
11048
|
+
updated_at: SEED_ISO
|
|
11049
|
+
};
|
|
11050
|
+
registry.products.put(id, product);
|
|
11051
|
+
if (categoryId) {
|
|
11052
|
+
const cat = registry.categories.get(categoryId);
|
|
11053
|
+
if (cat && !cat.product_ids.includes(id)) cat.product_ids.push(id);
|
|
11054
|
+
}
|
|
11055
|
+
if (collectionId) {
|
|
11056
|
+
const col = registry.collections.get(collectionId);
|
|
11057
|
+
if (col && !col.product_ids.includes(id)) col.product_ids.push(id);
|
|
11058
|
+
}
|
|
11059
|
+
return product;
|
|
11060
|
+
},
|
|
11061
|
+
service(input) {
|
|
11062
|
+
const business = requireBusiness();
|
|
11063
|
+
const id = `${ID_PREFIX.service}${slugify(input.name)}`;
|
|
11064
|
+
const service = {
|
|
11065
|
+
id,
|
|
11066
|
+
business_id: business.id,
|
|
11067
|
+
name: input.name,
|
|
11068
|
+
description: input.description,
|
|
11069
|
+
duration_minutes: input.durationMinutes,
|
|
11070
|
+
price: input.price,
|
|
11071
|
+
is_available: true
|
|
11072
|
+
};
|
|
11073
|
+
registry.services.put(id, service);
|
|
11074
|
+
return service;
|
|
11075
|
+
},
|
|
11076
|
+
image: seedImage,
|
|
11077
|
+
extend(name) {
|
|
11078
|
+
const result = applySeed(registry, name);
|
|
11079
|
+
current = registry.businesses.get(result.businessId) ?? current;
|
|
11080
|
+
return result;
|
|
11081
|
+
}
|
|
11082
|
+
};
|
|
11083
|
+
}
|
|
11084
|
+
|
|
11085
|
+
// src/mock/seeds/source.ts
|
|
11086
|
+
var SNAPSHOT_META_KEY = "__meta";
|
|
11087
|
+
function loadSnapshot(registry, data, businessId) {
|
|
11088
|
+
applySnapshot(registry, data);
|
|
11089
|
+
if (businessId) return { businessId };
|
|
11090
|
+
const meta = data[SNAPSHOT_META_KEY];
|
|
11091
|
+
if (meta?.defaultBusinessId) return { businessId: meta.defaultBusinessId };
|
|
11092
|
+
const businesses = registry.businesses.list();
|
|
11093
|
+
if (businesses.length === 1) return { businessId: businesses[0].id };
|
|
11094
|
+
if (businesses.length === 0) {
|
|
11095
|
+
throw new Error("Seed snapshot has no business. Add one, or set __meta.defaultBusinessId.");
|
|
11096
|
+
}
|
|
11097
|
+
throw new Error(
|
|
11098
|
+
`Seed snapshot has ${businesses.length} businesses; set __meta.defaultBusinessId to pick one.`
|
|
11099
|
+
);
|
|
11100
|
+
}
|
|
11101
|
+
function resolveSeed(registry, source) {
|
|
11102
|
+
if (typeof source === "string") return applySeed(registry, source);
|
|
11103
|
+
switch (source.kind) {
|
|
11104
|
+
case "builtin":
|
|
11105
|
+
return applySeed(registry, source.name);
|
|
11106
|
+
case "json":
|
|
11107
|
+
return loadSnapshot(registry, source.data, source.businessId);
|
|
11108
|
+
case "fn":
|
|
11109
|
+
return source.seed(makeSeedContext(registry));
|
|
11110
|
+
}
|
|
11111
|
+
}
|
|
11112
|
+
|
|
10903
11113
|
// src/mock/deps.ts
|
|
10904
11114
|
function createDeps(options = {}) {
|
|
10905
11115
|
const clock = createClock({ frozenAt: options.frozenAt });
|
|
10906
11116
|
const ids = createIdGen(options.rngSeed);
|
|
10907
11117
|
const bus = createBus({ idGen: () => ids.raw("evt"), clock: () => clock.now() });
|
|
10908
11118
|
const registry = createStateRegistry();
|
|
10909
|
-
const
|
|
10910
|
-
|
|
10911
|
-
let defaultBusinessId = seedResult.businessId;
|
|
11119
|
+
const seedSource = options.seed ?? "default";
|
|
11120
|
+
let defaultBusinessId = resolveSeed(registry, seedSource).businessId;
|
|
10912
11121
|
const auth = createAuthService({
|
|
10913
11122
|
registry,
|
|
10914
11123
|
clock,
|
|
@@ -10962,11 +11171,10 @@ function createDeps(options = {}) {
|
|
|
10962
11171
|
return defaultBusinessId;
|
|
10963
11172
|
},
|
|
10964
11173
|
chaos,
|
|
10965
|
-
resetAll(
|
|
11174
|
+
resetAll(next) {
|
|
10966
11175
|
for (const store of Object.values(registry)) store.reset();
|
|
10967
11176
|
bus.clear();
|
|
10968
|
-
|
|
10969
|
-
defaultBusinessId = r.businessId;
|
|
11177
|
+
defaultBusinessId = resolveSeed(registry, next ?? seedSource).businessId;
|
|
10970
11178
|
return defaultBusinessId;
|
|
10971
11179
|
}
|
|
10972
11180
|
};
|
|
@@ -11042,11 +11250,7 @@ function createMockApp(options = {}) {
|
|
|
11042
11250
|
function loadFromFile(reg, path) {
|
|
11043
11251
|
if (!existsSync(path)) return false;
|
|
11044
11252
|
try {
|
|
11045
|
-
|
|
11046
|
-
for (const [k, v] of Object.entries(data)) {
|
|
11047
|
-
const store = reg[k];
|
|
11048
|
-
if (store) store.loadJSON(v);
|
|
11049
|
-
}
|
|
11253
|
+
applySnapshot(reg, JSON.parse(readFileSync(path, "utf8")));
|
|
11050
11254
|
return true;
|
|
11051
11255
|
} catch {
|
|
11052
11256
|
return false;
|
|
@@ -11109,11 +11313,18 @@ function setupWebhooks(bus, opts) {
|
|
|
11109
11313
|
}
|
|
11110
11314
|
|
|
11111
11315
|
// src/mock/cli.ts
|
|
11316
|
+
var CONVENTION_FILES = [
|
|
11317
|
+
"cimplify.seed.json",
|
|
11318
|
+
"cimplify.seed.mjs",
|
|
11319
|
+
"cimplify.seed.js",
|
|
11320
|
+
"cimplify.seed.ts"
|
|
11321
|
+
];
|
|
11112
11322
|
function parseArgs(argv) {
|
|
11113
11323
|
const opts = {
|
|
11114
11324
|
port: Number(process.env.CIMPLIFY_MOCK_PORT) || 8787,
|
|
11115
11325
|
host: process.env.CIMPLIFY_MOCK_HOST ?? "127.0.0.1",
|
|
11116
11326
|
seed: "default",
|
|
11327
|
+
seedExplicit: false,
|
|
11117
11328
|
authMode: "permissive",
|
|
11118
11329
|
defaultOtp: "123456",
|
|
11119
11330
|
cors: "*",
|
|
@@ -11132,6 +11343,16 @@ function parseArgs(argv) {
|
|
|
11132
11343
|
break;
|
|
11133
11344
|
case "--seed":
|
|
11134
11345
|
opts.seed = next();
|
|
11346
|
+
opts.seedExplicit = true;
|
|
11347
|
+
break;
|
|
11348
|
+
case "--seed-file":
|
|
11349
|
+
opts.seedFile = next();
|
|
11350
|
+
break;
|
|
11351
|
+
case "--seed-module":
|
|
11352
|
+
opts.seedModule = next();
|
|
11353
|
+
break;
|
|
11354
|
+
case "--dump":
|
|
11355
|
+
opts.dump = next();
|
|
11135
11356
|
break;
|
|
11136
11357
|
case "--auth-mode":
|
|
11137
11358
|
opts.authMode = next();
|
|
@@ -11185,14 +11406,24 @@ function printHelp() {
|
|
|
11185
11406
|
Usage:
|
|
11186
11407
|
cimplify-mock [flags]
|
|
11187
11408
|
|
|
11188
|
-
|
|
11409
|
+
Seed (choose one; flags win over a cimplify.seed.* file in the cwd):
|
|
11410
|
+
--seed <name> Built-in seed: default | empty | restaurant | retail |
|
|
11411
|
+
services | grocery | fashion | pharmacy | auto |
|
|
11412
|
+
reesa-storefront
|
|
11413
|
+
--seed-file <file.json> Boot from a JSON snapshot (dump one with --dump, edit, reload)
|
|
11414
|
+
--seed-module <file> Boot from a module default-exporting a seed function
|
|
11415
|
+
(.mjs/.js anywhere; .ts needs bun)
|
|
11416
|
+
--dump <file.json> Seed, write the state snapshot to <file>, and exit
|
|
11417
|
+
(convention) With no seed flag, a cimplify.seed.{json,mjs,js,ts} in
|
|
11418
|
+
the cwd is loaded automatically
|
|
11419
|
+
|
|
11420
|
+
Server:
|
|
11189
11421
|
--port, -p <num> Port to listen on (default 8787)
|
|
11190
11422
|
--host <host> Host to bind (default 127.0.0.1)
|
|
11191
|
-
--seed <name> default | restaurant | retail | services | grocery | fashion | reesa-storefront | empty
|
|
11192
11423
|
--auth-mode <mode> permissive (auto-mint sessions) | strict
|
|
11193
11424
|
--otp <code> Default OTP code (default 123456)
|
|
11194
11425
|
--seed-rng <n> Deterministic RNG seed
|
|
11195
|
-
--persist <file> Persist state to JSON file
|
|
11426
|
+
--persist <file> Persist live state to a JSON file (restore on restart)
|
|
11196
11427
|
--cors <origins> CORS origins (comma-separated, or '*')
|
|
11197
11428
|
--webhook-url <url> Send mock events to this URL
|
|
11198
11429
|
--webhook-secret <key> HMAC secret for webhook signatures
|
|
@@ -11202,16 +11433,75 @@ Flags:
|
|
|
11202
11433
|
--help, -h
|
|
11203
11434
|
`);
|
|
11204
11435
|
}
|
|
11436
|
+
function resolvePath(file) {
|
|
11437
|
+
return isAbsolute(file) ? file : resolve(process.cwd(), file);
|
|
11438
|
+
}
|
|
11439
|
+
function readSnapshot(file) {
|
|
11440
|
+
const abs = resolvePath(file);
|
|
11441
|
+
if (!existsSync(abs)) throw new Error(`Seed file not found: ${file}`);
|
|
11442
|
+
return JSON.parse(readFileSync(abs, "utf8"));
|
|
11443
|
+
}
|
|
11444
|
+
async function loadSeedModule(file) {
|
|
11445
|
+
const abs = resolvePath(file);
|
|
11446
|
+
if (!existsSync(abs)) throw new Error(`Seed module not found: ${file}`);
|
|
11447
|
+
let mod;
|
|
11448
|
+
try {
|
|
11449
|
+
mod = await import(pathToFileURL(abs).href);
|
|
11450
|
+
} catch (err) {
|
|
11451
|
+
if (abs.endsWith(".ts") && /Unknown file extension|UNKNOWN_FILE_EXTENSION/i.test(String(err))) {
|
|
11452
|
+
throw new Error(
|
|
11453
|
+
`TypeScript seed modules need a TS-capable runtime. Run via bun (\`bunx @cimplify/sdk mock --seed-module ${file}\`), or use a .mjs/.js/.json seed.`
|
|
11454
|
+
);
|
|
11455
|
+
}
|
|
11456
|
+
throw err;
|
|
11457
|
+
}
|
|
11458
|
+
const seed = mod.default ?? mod.seed;
|
|
11459
|
+
if (typeof seed !== "function") {
|
|
11460
|
+
throw new Error(`Seed module ${file} must default-export a seed function (see defineSeed).`);
|
|
11461
|
+
}
|
|
11462
|
+
return seed;
|
|
11463
|
+
}
|
|
11464
|
+
function discoverConventionSeed() {
|
|
11465
|
+
for (const name of CONVENTION_FILES) {
|
|
11466
|
+
const abs = resolve(process.cwd(), name);
|
|
11467
|
+
if (existsSync(abs)) return abs;
|
|
11468
|
+
}
|
|
11469
|
+
return null;
|
|
11470
|
+
}
|
|
11471
|
+
async function resolveSeedSource(opts) {
|
|
11472
|
+
if (opts.seedFile) {
|
|
11473
|
+
return { source: { kind: "json", data: readSnapshot(opts.seedFile) }, label: `file: ${opts.seedFile}` };
|
|
11474
|
+
}
|
|
11475
|
+
if (opts.seedModule) {
|
|
11476
|
+
return { source: { kind: "fn", seed: await loadSeedModule(opts.seedModule) }, label: `module: ${opts.seedModule}` };
|
|
11477
|
+
}
|
|
11478
|
+
if (!opts.seedExplicit) {
|
|
11479
|
+
const found = discoverConventionSeed();
|
|
11480
|
+
if (found) {
|
|
11481
|
+
const label = `convention: ${basename(found)}`;
|
|
11482
|
+
if (found.endsWith(".json")) return { source: { kind: "json", data: readSnapshot(found) }, label };
|
|
11483
|
+
return { source: { kind: "fn", seed: await loadSeedModule(found) }, label };
|
|
11484
|
+
}
|
|
11485
|
+
}
|
|
11486
|
+
return { source: opts.seed, label: opts.seed };
|
|
11487
|
+
}
|
|
11205
11488
|
async function main() {
|
|
11206
11489
|
const opts = parseArgs(process.argv.slice(2));
|
|
11490
|
+
const { source, label } = await resolveSeedSource(opts);
|
|
11207
11491
|
const handle = createMockApp({
|
|
11208
|
-
seed:
|
|
11492
|
+
seed: source,
|
|
11209
11493
|
authMode: opts.authMode,
|
|
11210
11494
|
defaultOtp: opts.defaultOtp,
|
|
11211
11495
|
rngSeed: opts.rngSeed,
|
|
11212
11496
|
cors: opts.cors,
|
|
11213
11497
|
frozenAt: opts.frozenAt
|
|
11214
11498
|
});
|
|
11499
|
+
if (opts.dump) {
|
|
11500
|
+
const out = resolvePath(opts.dump);
|
|
11501
|
+
persistToFile(handle.deps.registry, out);
|
|
11502
|
+
console.log(`dumped ${label} \u2192 ${opts.dump} (business: ${handle.deps.defaultBusinessId})`);
|
|
11503
|
+
return;
|
|
11504
|
+
}
|
|
11215
11505
|
if (opts.persist) {
|
|
11216
11506
|
const loaded = loadFromFile(handle.deps.registry, opts.persist);
|
|
11217
11507
|
autoPersist(handle.deps.registry, opts.persist);
|
|
@@ -11232,7 +11522,7 @@ async function main() {
|
|
|
11232
11522
|
}
|
|
11233
11523
|
serve({ fetch: handle.app.fetch, port: opts.port, hostname: opts.host }, () => {
|
|
11234
11524
|
console.log(`@cimplify/sdk/mock listening on http://${opts.host}:${opts.port}`);
|
|
11235
|
-
console.log(` seed: ${
|
|
11525
|
+
console.log(` seed: ${label} (business: ${handle.deps.defaultBusinessId})`);
|
|
11236
11526
|
console.log(` state: ${opts.persist ? `persisted at ${opts.persist}` : "in-memory"}`);
|
|
11237
11527
|
console.log(` admin: http://${opts.host}:${opts.port}/_mock`);
|
|
11238
11528
|
console.log(` events: http://${opts.host}:${opts.port}/_mock/events/stream (SSE)`);
|
|
@@ -11241,6 +11531,6 @@ async function main() {
|
|
|
11241
11531
|
});
|
|
11242
11532
|
}
|
|
11243
11533
|
main().catch((err) => {
|
|
11244
|
-
console.error("Failed to start:", err);
|
|
11534
|
+
console.error("Failed to start:", err instanceof Error ? err.message : err);
|
|
11245
11535
|
process.exit(1);
|
|
11246
11536
|
});
|
package/dist/mock/library.js
CHANGED
|
@@ -5901,6 +5901,14 @@ function createLinkService({ clock, ids }) {
|
|
|
5901
5901
|
};
|
|
5902
5902
|
}
|
|
5903
5903
|
|
|
5904
|
+
// src/mock/state/snapshot.ts
|
|
5905
|
+
function applySnapshot(reg, data) {
|
|
5906
|
+
for (const [k, v] of Object.entries(data)) {
|
|
5907
|
+
const store = reg[k];
|
|
5908
|
+
if (store) store.loadJSON(v);
|
|
5909
|
+
}
|
|
5910
|
+
}
|
|
5911
|
+
|
|
5904
5912
|
// src/mock/seeds/image.ts
|
|
5905
5913
|
var CDN_BASE_URL = "https://static-tmp.cimplify.io";
|
|
5906
5914
|
function seedImage(industry, slug) {
|
|
@@ -10268,15 +10276,217 @@ function applySeed(registry, name) {
|
|
|
10268
10276
|
return fn(registry);
|
|
10269
10277
|
}
|
|
10270
10278
|
|
|
10279
|
+
// src/mock/seeds/context.ts
|
|
10280
|
+
var SEED_ISO = "2026-01-01T00:00:00.000Z";
|
|
10281
|
+
var ID_PREFIX = {
|
|
10282
|
+
business: "bus_",
|
|
10283
|
+
category: "cat_",
|
|
10284
|
+
collection: "col_",
|
|
10285
|
+
product: "prod_",
|
|
10286
|
+
service: "svc_"
|
|
10287
|
+
};
|
|
10288
|
+
var DEFAULT_CURRENCY = "GHS";
|
|
10289
|
+
function slugify(value) {
|
|
10290
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
10291
|
+
}
|
|
10292
|
+
function makeSeedContext(registry) {
|
|
10293
|
+
let current;
|
|
10294
|
+
const requireBusiness = () => {
|
|
10295
|
+
if (current) return current;
|
|
10296
|
+
const sole = registry.businesses.list();
|
|
10297
|
+
if (sole.length === 1) {
|
|
10298
|
+
current = sole[0];
|
|
10299
|
+
return current;
|
|
10300
|
+
}
|
|
10301
|
+
throw new Error("Seed must create a business (ctx.business) before adding child records.");
|
|
10302
|
+
};
|
|
10303
|
+
const resolveCategoryId = (cat) => {
|
|
10304
|
+
if (!cat) return void 0;
|
|
10305
|
+
if (typeof cat !== "string") return cat.id;
|
|
10306
|
+
if (registry.categories.get(cat)) return cat;
|
|
10307
|
+
return registry.categories.list().find((c) => c.slug === cat)?.id;
|
|
10308
|
+
};
|
|
10309
|
+
const resolveCollectionId = (col) => {
|
|
10310
|
+
if (!col) return void 0;
|
|
10311
|
+
if (typeof col !== "string") return col.id;
|
|
10312
|
+
if (registry.collections.get(col)) return col;
|
|
10313
|
+
return registry.collections.list().find((c) => c.slug === col)?.id;
|
|
10314
|
+
};
|
|
10315
|
+
return {
|
|
10316
|
+
registry,
|
|
10317
|
+
business(input) {
|
|
10318
|
+
const handle = input.handle ?? slugify(input.name);
|
|
10319
|
+
const id = `${ID_PREFIX.business}${slugify(handle)}`;
|
|
10320
|
+
const business = {
|
|
10321
|
+
business_type: "other",
|
|
10322
|
+
email: `hello@${handle}.test`,
|
|
10323
|
+
default_currency: DEFAULT_CURRENCY,
|
|
10324
|
+
default_offers_table_service: false,
|
|
10325
|
+
default_accepts_online_orders: true,
|
|
10326
|
+
status: "active",
|
|
10327
|
+
created_by: "seed",
|
|
10328
|
+
preferences: {},
|
|
10329
|
+
is_online_only: true,
|
|
10330
|
+
enabled_payment_types: ["mobile_money"],
|
|
10331
|
+
default_location_settings: {},
|
|
10332
|
+
country_code: "GH",
|
|
10333
|
+
timezone: "Africa/Accra",
|
|
10334
|
+
...input,
|
|
10335
|
+
id,
|
|
10336
|
+
handle,
|
|
10337
|
+
created_at: input.created_at ?? SEED_ISO,
|
|
10338
|
+
updated_at: input.updated_at ?? SEED_ISO
|
|
10339
|
+
};
|
|
10340
|
+
registry.businesses.put(id, business);
|
|
10341
|
+
current = business;
|
|
10342
|
+
return business;
|
|
10343
|
+
},
|
|
10344
|
+
category(input) {
|
|
10345
|
+
const business = requireBusiness();
|
|
10346
|
+
const slug = input.slug ?? slugify(input.name);
|
|
10347
|
+
const id = `${ID_PREFIX.category}${slug}`;
|
|
10348
|
+
const category = {
|
|
10349
|
+
id,
|
|
10350
|
+
business_id: business.id,
|
|
10351
|
+
name: input.name,
|
|
10352
|
+
slug,
|
|
10353
|
+
description: input.description,
|
|
10354
|
+
image: input.image,
|
|
10355
|
+
product_ids: [],
|
|
10356
|
+
display_order: input.displayOrder ?? 0,
|
|
10357
|
+
is_active: true,
|
|
10358
|
+
created_at: SEED_ISO,
|
|
10359
|
+
updated_at: SEED_ISO
|
|
10360
|
+
};
|
|
10361
|
+
registry.categories.put(id, category);
|
|
10362
|
+
return category;
|
|
10363
|
+
},
|
|
10364
|
+
collection(input) {
|
|
10365
|
+
const business = requireBusiness();
|
|
10366
|
+
const slug = input.slug ?? slugify(input.name);
|
|
10367
|
+
const id = `${ID_PREFIX.collection}${slug}`;
|
|
10368
|
+
const collection = {
|
|
10369
|
+
id,
|
|
10370
|
+
business_id: business.id,
|
|
10371
|
+
name: input.name,
|
|
10372
|
+
slug,
|
|
10373
|
+
description: input.description,
|
|
10374
|
+
product_ids: [],
|
|
10375
|
+
is_active: true,
|
|
10376
|
+
created_at: SEED_ISO,
|
|
10377
|
+
updated_at: SEED_ISO
|
|
10378
|
+
};
|
|
10379
|
+
registry.collections.put(id, collection);
|
|
10380
|
+
return collection;
|
|
10381
|
+
},
|
|
10382
|
+
product(input) {
|
|
10383
|
+
const business = requireBusiness();
|
|
10384
|
+
const slug = input.slug ?? slugify(input.name);
|
|
10385
|
+
const id = `${ID_PREFIX.product}${slug}`;
|
|
10386
|
+
const categoryId = resolveCategoryId(input.category);
|
|
10387
|
+
const collectionId = resolveCollectionId(input.collection);
|
|
10388
|
+
const product = {
|
|
10389
|
+
id,
|
|
10390
|
+
business_id: business.id,
|
|
10391
|
+
name: input.name,
|
|
10392
|
+
slug,
|
|
10393
|
+
description: input.description,
|
|
10394
|
+
product_type: input.productType ?? "product",
|
|
10395
|
+
base_price: input.price,
|
|
10396
|
+
currency: input.currency ?? business.default_currency,
|
|
10397
|
+
image: input.image,
|
|
10398
|
+
images: input.images ?? (input.image ? [input.image] : []),
|
|
10399
|
+
is_available: true,
|
|
10400
|
+
category_ids: categoryId ? [categoryId] : [],
|
|
10401
|
+
collection_ids: collectionId ? [collectionId] : [],
|
|
10402
|
+
add_on_ids: [],
|
|
10403
|
+
variant_ids: [],
|
|
10404
|
+
tags: input.tags ?? [],
|
|
10405
|
+
calories: input.calories,
|
|
10406
|
+
allergies: input.allergies ?? [],
|
|
10407
|
+
ingredients: input.ingredients ?? [],
|
|
10408
|
+
pairings: [],
|
|
10409
|
+
is_signature: input.isSignature ?? false,
|
|
10410
|
+
is_new: input.isNew ?? false,
|
|
10411
|
+
duration_minutes: input.durationMinutes,
|
|
10412
|
+
metadata: input.metadata,
|
|
10413
|
+
created_at: SEED_ISO,
|
|
10414
|
+
updated_at: SEED_ISO
|
|
10415
|
+
};
|
|
10416
|
+
registry.products.put(id, product);
|
|
10417
|
+
if (categoryId) {
|
|
10418
|
+
const cat = registry.categories.get(categoryId);
|
|
10419
|
+
if (cat && !cat.product_ids.includes(id)) cat.product_ids.push(id);
|
|
10420
|
+
}
|
|
10421
|
+
if (collectionId) {
|
|
10422
|
+
const col = registry.collections.get(collectionId);
|
|
10423
|
+
if (col && !col.product_ids.includes(id)) col.product_ids.push(id);
|
|
10424
|
+
}
|
|
10425
|
+
return product;
|
|
10426
|
+
},
|
|
10427
|
+
service(input) {
|
|
10428
|
+
const business = requireBusiness();
|
|
10429
|
+
const id = `${ID_PREFIX.service}${slugify(input.name)}`;
|
|
10430
|
+
const service = {
|
|
10431
|
+
id,
|
|
10432
|
+
business_id: business.id,
|
|
10433
|
+
name: input.name,
|
|
10434
|
+
description: input.description,
|
|
10435
|
+
duration_minutes: input.durationMinutes,
|
|
10436
|
+
price: input.price,
|
|
10437
|
+
is_available: true
|
|
10438
|
+
};
|
|
10439
|
+
registry.services.put(id, service);
|
|
10440
|
+
return service;
|
|
10441
|
+
},
|
|
10442
|
+
image: seedImage,
|
|
10443
|
+
extend(name) {
|
|
10444
|
+
const result = applySeed(registry, name);
|
|
10445
|
+
current = registry.businesses.get(result.businessId) ?? current;
|
|
10446
|
+
return result;
|
|
10447
|
+
}
|
|
10448
|
+
};
|
|
10449
|
+
}
|
|
10450
|
+
function defineSeed(seed) {
|
|
10451
|
+
return seed;
|
|
10452
|
+
}
|
|
10453
|
+
|
|
10454
|
+
// src/mock/seeds/source.ts
|
|
10455
|
+
var SNAPSHOT_META_KEY = "__meta";
|
|
10456
|
+
function loadSnapshot(registry, data, businessId) {
|
|
10457
|
+
applySnapshot(registry, data);
|
|
10458
|
+
if (businessId) return { businessId };
|
|
10459
|
+
const meta = data[SNAPSHOT_META_KEY];
|
|
10460
|
+
if (meta?.defaultBusinessId) return { businessId: meta.defaultBusinessId };
|
|
10461
|
+
const businesses = registry.businesses.list();
|
|
10462
|
+
if (businesses.length === 1) return { businessId: businesses[0].id };
|
|
10463
|
+
if (businesses.length === 0) {
|
|
10464
|
+
throw new Error("Seed snapshot has no business. Add one, or set __meta.defaultBusinessId.");
|
|
10465
|
+
}
|
|
10466
|
+
throw new Error(
|
|
10467
|
+
`Seed snapshot has ${businesses.length} businesses; set __meta.defaultBusinessId to pick one.`
|
|
10468
|
+
);
|
|
10469
|
+
}
|
|
10470
|
+
function resolveSeed(registry, source) {
|
|
10471
|
+
if (typeof source === "string") return applySeed(registry, source);
|
|
10472
|
+
switch (source.kind) {
|
|
10473
|
+
case "builtin":
|
|
10474
|
+
return applySeed(registry, source.name);
|
|
10475
|
+
case "json":
|
|
10476
|
+
return loadSnapshot(registry, source.data, source.businessId);
|
|
10477
|
+
case "fn":
|
|
10478
|
+
return source.seed(makeSeedContext(registry));
|
|
10479
|
+
}
|
|
10480
|
+
}
|
|
10481
|
+
|
|
10271
10482
|
// src/mock/deps.ts
|
|
10272
10483
|
function createDeps(options = {}) {
|
|
10273
10484
|
const clock = createClock({ frozenAt: options.frozenAt });
|
|
10274
10485
|
const ids = createIdGen(options.rngSeed);
|
|
10275
10486
|
const bus = createBus({ idGen: () => ids.raw("evt"), clock: () => clock.now() });
|
|
10276
10487
|
const registry = createStateRegistry();
|
|
10277
|
-
const
|
|
10278
|
-
|
|
10279
|
-
let defaultBusinessId = seedResult.businessId;
|
|
10488
|
+
const seedSource = options.seed ?? "default";
|
|
10489
|
+
let defaultBusinessId = resolveSeed(registry, seedSource).businessId;
|
|
10280
10490
|
const auth = createAuthService({
|
|
10281
10491
|
registry,
|
|
10282
10492
|
clock,
|
|
@@ -10330,11 +10540,10 @@ function createDeps(options = {}) {
|
|
|
10330
10540
|
return defaultBusinessId;
|
|
10331
10541
|
},
|
|
10332
10542
|
chaos,
|
|
10333
|
-
resetAll(
|
|
10543
|
+
resetAll(next) {
|
|
10334
10544
|
for (const store of Object.values(registry)) store.reset();
|
|
10335
10545
|
bus.clear();
|
|
10336
|
-
|
|
10337
|
-
defaultBusinessId = r.businessId;
|
|
10546
|
+
defaultBusinessId = resolveSeed(registry, next ?? seedSource).businessId;
|
|
10338
10547
|
return defaultBusinessId;
|
|
10339
10548
|
}
|
|
10340
10549
|
};
|
|
@@ -10437,9 +10646,17 @@ function setupWebhooks(bus, opts) {
|
|
|
10437
10646
|
});
|
|
10438
10647
|
}
|
|
10439
10648
|
|
|
10649
|
+
exports.SEED_ISO = SEED_ISO;
|
|
10650
|
+
exports.SNAPSHOT_META_KEY = SNAPSHOT_META_KEY;
|
|
10440
10651
|
exports.applySeed = applySeed;
|
|
10652
|
+
exports.applySnapshot = applySnapshot;
|
|
10441
10653
|
exports.createDeps = createDeps;
|
|
10442
10654
|
exports.createMockApp = createMockApp;
|
|
10655
|
+
exports.defineSeed = defineSeed;
|
|
10656
|
+
exports.loadSnapshot = loadSnapshot;
|
|
10657
|
+
exports.makeSeedContext = makeSeedContext;
|
|
10658
|
+
exports.resolveSeed = resolveSeed;
|
|
10443
10659
|
exports.setupWebhooks = setupWebhooks;
|
|
10444
10660
|
exports.signPayload = signPayload;
|
|
10661
|
+
exports.slugify = slugify;
|
|
10445
10662
|
exports.verifySignature = verifySignature;
|