@pro-laico/payload-seed 0.0.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 (71) hide show
  1. package/LICENSE.md +22 -0
  2. package/README.md +9 -0
  3. package/dist/bin/seed.d.ts +9 -0
  4. package/dist/bin/seed.d.ts.map +1 -0
  5. package/dist/bin/seed.js +36 -0
  6. package/dist/bin/seed.js.map +1 -0
  7. package/dist/components/SeedButton.d.ts +11 -0
  8. package/dist/components/SeedButton.d.ts.map +1 -0
  9. package/dist/components/SeedButton.js +82 -0
  10. package/dist/components/SeedButton.js.map +1 -0
  11. package/dist/defineSeed.d.ts +43 -0
  12. package/dist/defineSeed.d.ts.map +1 -0
  13. package/dist/defineSeed.js +51 -0
  14. package/dist/defineSeed.js.map +1 -0
  15. package/dist/endpoint.d.ts +10 -0
  16. package/dist/endpoint.d.ts.map +1 -0
  17. package/dist/endpoint.js +60 -0
  18. package/dist/endpoint.js.map +1 -0
  19. package/dist/engine/files.d.ts +15 -0
  20. package/dist/engine/files.d.ts.map +1 -0
  21. package/dist/engine/files.js +72 -0
  22. package/dist/engine/files.js.map +1 -0
  23. package/dist/engine/graph.d.ts +61 -0
  24. package/dist/engine/graph.d.ts.map +1 -0
  25. package/dist/engine/graph.js +0 -0
  26. package/dist/engine/graph.js.map +1 -0
  27. package/dist/engine/run.d.ts +46 -0
  28. package/dist/engine/run.d.ts.map +1 -0
  29. package/dist/engine/run.js +387 -0
  30. package/dist/engine/run.js.map +1 -0
  31. package/dist/engine/tokens.d.ts +16 -0
  32. package/dist/engine/tokens.d.ts.map +1 -0
  33. package/dist/engine/tokens.js +37 -0
  34. package/dist/engine/tokens.js.map +1 -0
  35. package/dist/engine/validate.d.ts +28 -0
  36. package/dist/engine/validate.d.ts.map +1 -0
  37. package/dist/engine/validate.js +79 -0
  38. package/dist/engine/validate.js.map +1 -0
  39. package/dist/guard.d.ts +11 -0
  40. package/dist/guard.d.ts.map +1 -0
  41. package/dist/guard.js +11 -0
  42. package/dist/guard.js.map +1 -0
  43. package/dist/index.d.ts +9 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +13 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/options.d.ts +29 -0
  48. package/dist/options.d.ts.map +1 -0
  49. package/dist/options.js +10 -0
  50. package/dist/options.js.map +1 -0
  51. package/dist/plugin.d.ts +14 -0
  52. package/dist/plugin.d.ts.map +1 -0
  53. package/dist/plugin.js +73 -0
  54. package/dist/plugin.js.map +1 -0
  55. package/dist/refs.d.ts +56 -0
  56. package/dist/refs.d.ts.map +1 -0
  57. package/dist/refs.js +39 -0
  58. package/dist/refs.js.map +1 -0
  59. package/dist/registry.d.ts +31 -0
  60. package/dist/registry.d.ts.map +1 -0
  61. package/dist/registry.js +20 -0
  62. package/dist/registry.js.map +1 -0
  63. package/dist/typegen.d.ts +13 -0
  64. package/dist/typegen.d.ts.map +1 -0
  65. package/dist/typegen.js +40 -0
  66. package/dist/typegen.js.map +1 -0
  67. package/dist/types.d.ts +81 -0
  68. package/dist/types.d.ts.map +1 -0
  69. package/dist/types.js +3 -0
  70. package/dist/types.js.map +1 -0
  71. package/package.json +70 -0
@@ -0,0 +1,79 @@
1
+ import { isRef } from "../refs.js";
2
+ import { collectTokens, docNodeId } from "./tokens.js";
3
+ export class SeedValidationError extends Error {
4
+ issues;
5
+ constructor(issues){
6
+ super(`[payload-seed] seed data failed validation:\n${issues.map((i)=>` - ${i}`).join('\n')}`), this.issues = issues;
7
+ this.name = 'SeedValidationError';
8
+ }
9
+ }
10
+ // Keys that are valid on a record but aren't schema fields.
11
+ const ALLOWED_NON_FIELDS = new Set([
12
+ '_status'
13
+ ]);
14
+ /**
15
+ * Validate the built model against the declared docs and the live config: every definition's own
16
+ * slug exists in the config (as a collection or global, matching its kind); every `ref()`
17
+ * resolves to a seeded doc and references a real collection; every `_file` sits on a collection
18
+ * that can take one (an upload or `custom.seedAsset` collection); no duplicate `_key` within a collection
19
+ * (across every definition sharing the slug); and (when `fieldNames` is supplied) every record field
20
+ * exists in the schema. Collects ALL issues and throws once. (Cycle detection happens in the graph topo-sort.)
21
+ */ export function validateModel({ model, collectionSlugs, globalSlugs, fileCollections, fieldNames }) {
22
+ const issues = [];
23
+ const docIds = new Set();
24
+ for (const coll of model.collections)for (const rec of coll.records)docIds.add(docNodeId(coll.slug, rec.key));
25
+ // A definition's own slug must exist in the config, or the run would wipe collections and then die mid-create.
26
+ for (const coll of model.collections){
27
+ if (!collectionSlugs.has(coll.slug)) {
28
+ issues.push(`defineSeed('${coll.slug}'): no collection '${coll.slug}' in the Payload config - fix the slug or add the collection.`);
29
+ }
30
+ }
31
+ for (const g of model.globals){
32
+ if (!globalSlugs.has(g.slug)) {
33
+ issues.push(`defineSeed('${g.slug}'): no global '${g.slug}' in the Payload config - fix the slug or add the global.`);
34
+ }
35
+ }
36
+ const check = (where, data)=>{
37
+ for (const token of collectTokens(data)){
38
+ if (!isRef(token)) continue;
39
+ if (!collectionSlugs.has(token.collection)) {
40
+ issues.push(`${where}: ref('${token.collection}', '${token.key}') targets unknown collection '${token.collection}'.`);
41
+ } else if (!docIds.has(docNodeId(token.collection, token.key))) {
42
+ issues.push(`${where}: ref('${token.collection}', '${token.key}') - no seeded '${token.collection}' doc has _key '${token.key}'.`);
43
+ }
44
+ }
45
+ };
46
+ for (const coll of model.collections)for (const rec of coll.records)check(`${coll.slug}:${rec.key}`, rec.data);
47
+ for (const g of model.globals)check(`global:${g.slug}`, g.data);
48
+ // A `_file` only makes sense on an upload collection or a `custom.seedAsset` collection.
49
+ for (const coll of model.collections){
50
+ for (const rec of coll.records){
51
+ if (rec.file && !fileCollections.has(coll.slug)) {
52
+ issues.push(`${coll.slug}:${rec.key}: _file set, but '${coll.slug}' is not an upload collection or a custom.seedAsset collection.`);
53
+ }
54
+ }
55
+ }
56
+ // Unknown top-level fields (runtime counterpart to the compile-time exactness check).
57
+ const checkFields = (where, slug, data)=>{
58
+ const valid = fieldNames?.get(slug);
59
+ if (!valid) return;
60
+ for (const key of Object.keys(data)){
61
+ if (!valid.has(key) && !ALLOWED_NON_FIELDS.has(key)) issues.push(`${where}: unknown field '${key}' - not in the '${slug}' schema.`);
62
+ }
63
+ };
64
+ for (const coll of model.collections)for (const rec of coll.records)checkFields(`${coll.slug}:${rec.key}`, coll.slug, rec.data);
65
+ for (const g of model.globals)checkFields(`global:${g.slug}`, `global:${g.slug}`, g.data);
66
+ // Duplicate _key within a collection makes refs ambiguous - checked across every definition sharing the slug.
67
+ const seenBySlug = new Map();
68
+ for (const coll of model.collections){
69
+ const seen = seenBySlug.get(coll.slug) ?? new Set();
70
+ seenBySlug.set(coll.slug, seen);
71
+ for (const rec of coll.records){
72
+ if (seen.has(rec.key)) issues.push(`${coll.slug}: duplicate _key '${rec.key}'.`);
73
+ seen.add(rec.key);
74
+ }
75
+ }
76
+ if (issues.length) throw new SeedValidationError(issues);
77
+ }
78
+
79
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/engine/validate.ts"],"sourcesContent":["import { isRef } from '../refs'\nimport type { BuiltModel } from './graph'\nimport { collectTokens, docNodeId } from './tokens'\n\nexport class SeedValidationError extends Error {\n constructor(public issues: string[]) {\n super(`[payload-seed] seed data failed validation:\\n${issues.map((i) => ` - ${i}`).join('\\n')}`)\n this.name = 'SeedValidationError'\n }\n}\n\nexport interface ValidateArgs {\n model: BuiltModel\n /** Slugs of collections that actually exist in the Payload config. */\n collectionSlugs: Set<string>\n /** Slugs of globals that actually exist in the Payload config. */\n globalSlugs: Set<string>\n /** Slugs that can carry a `_file`: upload collections plus `custom.seedAsset` collections. */\n fileCollections: Set<string>\n /** Valid top-level field names per node (`collection` slug, or `global:<slug>`), from the\n * live config's `flattenedFields`. When provided, unknown record fields are flagged —\n * the runtime counterpart to the compile-time exactness check. */\n fieldNames?: Map<string, Set<string>>\n}\n\n// Keys that are valid on a record but aren't schema fields.\nconst ALLOWED_NON_FIELDS = new Set(['_status'])\n\n/**\n * Validate the built model against the declared docs and the live config: every definition's own\n * slug exists in the config (as a collection or global, matching its kind); every `ref()`\n * resolves to a seeded doc and references a real collection; every `_file` sits on a collection\n * that can take one (an upload or `custom.seedAsset` collection); no duplicate `_key` within a collection\n * (across every definition sharing the slug); and (when `fieldNames` is supplied) every record field\n * exists in the schema. Collects ALL issues and throws once. (Cycle detection happens in the graph topo-sort.)\n */\nexport function validateModel({ model, collectionSlugs, globalSlugs, fileCollections, fieldNames }: ValidateArgs): void {\n const issues: string[] = []\n const docIds = new Set<string>()\n for (const coll of model.collections) for (const rec of coll.records) docIds.add(docNodeId(coll.slug, rec.key))\n\n // A definition's own slug must exist in the config, or the run would wipe collections and then die mid-create.\n for (const coll of model.collections) {\n if (!collectionSlugs.has(coll.slug)) {\n issues.push(`defineSeed('${coll.slug}'): no collection '${coll.slug}' in the Payload config - fix the slug or add the collection.`)\n }\n }\n for (const g of model.globals) {\n if (!globalSlugs.has(g.slug)) {\n issues.push(`defineSeed('${g.slug}'): no global '${g.slug}' in the Payload config - fix the slug or add the global.`)\n }\n }\n\n const check = (where: string, data: unknown) => {\n for (const token of collectTokens(data)) {\n if (!isRef(token)) continue\n if (!collectionSlugs.has(token.collection)) {\n issues.push(`${where}: ref('${token.collection}', '${token.key}') targets unknown collection '${token.collection}'.`)\n } else if (!docIds.has(docNodeId(token.collection, token.key))) {\n issues.push(`${where}: ref('${token.collection}', '${token.key}') - no seeded '${token.collection}' doc has _key '${token.key}'.`)\n }\n }\n }\n\n for (const coll of model.collections) for (const rec of coll.records) check(`${coll.slug}:${rec.key}`, rec.data)\n for (const g of model.globals) check(`global:${g.slug}`, g.data)\n\n // A `_file` only makes sense on an upload collection or a `custom.seedAsset` collection.\n for (const coll of model.collections) {\n for (const rec of coll.records) {\n if (rec.file && !fileCollections.has(coll.slug)) {\n issues.push(`${coll.slug}:${rec.key}: _file set, but '${coll.slug}' is not an upload collection or a custom.seedAsset collection.`)\n }\n }\n }\n\n // Unknown top-level fields (runtime counterpart to the compile-time exactness check).\n const checkFields = (where: string, slug: string, data: Record<string, unknown>) => {\n const valid = fieldNames?.get(slug)\n if (!valid) return\n for (const key of Object.keys(data)) {\n if (!valid.has(key) && !ALLOWED_NON_FIELDS.has(key)) issues.push(`${where}: unknown field '${key}' - not in the '${slug}' schema.`)\n }\n }\n for (const coll of model.collections) for (const rec of coll.records) checkFields(`${coll.slug}:${rec.key}`, coll.slug, rec.data)\n for (const g of model.globals) checkFields(`global:${g.slug}`, `global:${g.slug}`, g.data)\n\n // Duplicate _key within a collection makes refs ambiguous - checked across every definition sharing the slug.\n const seenBySlug = new Map<string, Set<string>>()\n for (const coll of model.collections) {\n const seen = seenBySlug.get(coll.slug) ?? new Set<string>()\n seenBySlug.set(coll.slug, seen)\n for (const rec of coll.records) {\n if (seen.has(rec.key)) issues.push(`${coll.slug}: duplicate _key '${rec.key}'.`)\n seen.add(rec.key)\n }\n }\n\n if (issues.length) throw new SeedValidationError(issues)\n}\n"],"names":["isRef","collectTokens","docNodeId","SeedValidationError","Error","issues","map","i","join","name","ALLOWED_NON_FIELDS","Set","validateModel","model","collectionSlugs","globalSlugs","fileCollections","fieldNames","docIds","coll","collections","rec","records","add","slug","key","has","push","g","globals","check","where","data","token","collection","file","checkFields","valid","get","Object","keys","seenBySlug","Map","seen","set","length"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Master kill switch for the destructive seed. Both run paths — a CLI runner and the
3
+ * in-app `POST /api/seed` endpoint — refuse to run unless `ENABLE_SEED` is exactly
4
+ * `"true"`. The seed WIPES whole collections, so it stays off by default: opt in
5
+ * per-environment by setting `ENABLE_SEED=true` while iterating, and never set it in
6
+ * production. The gate lives only on the entry points, never inside the engine, so an
7
+ * integration test can drive the real seed directly.
8
+ */
9
+ export declare const seedingEnabled: () => boolean;
10
+ export declare const SEED_DISABLED_MESSAGE = "Seeding is disabled. Set ENABLE_SEED=true to enable it (DESTRUCTIVE: wipes the seeded collections).";
11
+ //# sourceMappingURL=guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,QAAO,OAA6C,CAAA;AAE/E,eAAO,MAAM,qBAAqB,wGAAwG,CAAA"}
package/dist/guard.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Master kill switch for the destructive seed. Both run paths — a CLI runner and the
3
+ * in-app `POST /api/seed` endpoint — refuse to run unless `ENABLE_SEED` is exactly
4
+ * `"true"`. The seed WIPES whole collections, so it stays off by default: opt in
5
+ * per-environment by setting `ENABLE_SEED=true` while iterating, and never set it in
6
+ * production. The gate lives only on the entry points, never inside the engine, so an
7
+ * integration test can drive the real seed directly.
8
+ */ export const seedingEnabled = ()=>process.env.ENABLE_SEED === 'true';
9
+ export const SEED_DISABLED_MESSAGE = 'Seeding is disabled. Set ENABLE_SEED=true to enable it (DESTRUCTIVE: wipes the seeded collections).';
10
+
11
+ //# sourceMappingURL=guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/guard.ts"],"sourcesContent":["/**\n * Master kill switch for the destructive seed. Both run paths — a CLI runner and the\n * in-app `POST /api/seed` endpoint — refuse to run unless `ENABLE_SEED` is exactly\n * `\"true\"`. The seed WIPES whole collections, so it stays off by default: opt in\n * per-environment by setting `ENABLE_SEED=true` while iterating, and never set it in\n * production. The gate lives only on the entry points, never inside the engine, so an\n * integration test can drive the real seed directly.\n */\nexport const seedingEnabled = (): boolean => process.env.ENABLE_SEED === 'true'\n\nexport const SEED_DISABLED_MESSAGE = 'Seeding is disabled. Set ENABLE_SEED=true to enable it (DESTRUCTIVE: wipes the seeded collections).'\n"],"names":["seedingEnabled","process","env","ENABLE_SEED","SEED_DISABLED_MESSAGE"],"mappings":"AAAA;;;;;;;CAOC,GACD,OAAO,MAAMA,iBAAiB,IAAeC,QAAQC,GAAG,CAACC,WAAW,KAAK,OAAM;AAE/E,OAAO,MAAMC,wBAAwB,sGAAqG"}
@@ -0,0 +1,9 @@
1
+ export { seedPlugin } from './plugin';
2
+ export type { SeedPluginOptions } from './options';
3
+ export { defineSeed } from './defineSeed';
4
+ export type { SeedRegistry } from './registry';
5
+ export type { CollectionSeedData, GlobalSeedData, SeedTokens, WithRefs } from './types';
6
+ export type { FileToken, Ref } from './refs';
7
+ export { file, isFileToken, isRef, ref } from './refs';
8
+ export { seed } from './engine/run';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAKlD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAGzC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAM9C,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACvF,YAAY,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAA;AAG5C,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAA;AAGtD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ // The plugin
2
+ export { seedPlugin } from "./plugin.js";
3
+ // Authoring: define seed data (the `ref` / `file` tokens are supplied to each builder callback —
4
+ // `defineSeed('x', ({ ref, file }) => …)` — so they aren't imported). One helper for both:
5
+ // `defineSeed` infers collection (array of records) vs global (single object) from the slug.
6
+ export { defineSeed } from "./defineSeed.js";
7
+ // The token constructors themselves, for code that builds seed data OUTSIDE a builder
8
+ // callback — e.g. unit tests exercising a composed seed fragment directly.
9
+ export { file, isFileToken, isRef, ref } from "./refs.js";
10
+ // Run the seed from a script or test (the `payload seed` command and endpoint use this)
11
+ export { seed } from "./engine/run.js";
12
+
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// The plugin\nexport { seedPlugin } from './plugin'\nexport type { SeedPluginOptions } from './options'\n\n// Authoring: define seed data (the `ref` / `file` tokens are supplied to each builder callback —\n// `defineSeed('x', ({ ref, file }) => …)` — so they aren't imported). One helper for both:\n// `defineSeed` infers collection (array of records) vs global (single object) from the slug.\nexport { defineSeed } from './defineSeed'\n\n// The augmentable interface that generated types fill in (so `ref` keys are typed)\nexport type { SeedRegistry } from './registry'\n\n// Authoring types for seed helpers COMPOSED across files (e.g. per-block seed fragments that a\n// page definition assembles): `SeedTokens` types a helper's `{ ref, file }` parameter, `WithRefs`\n// widens a generated data type so `Ref` tokens may sit in relationship fields, and `Ref` /\n// `FileToken` are the token value types themselves.\nexport type { CollectionSeedData, GlobalSeedData, SeedTokens, WithRefs } from './types'\nexport type { FileToken, Ref } from './refs'\n// The token constructors themselves, for code that builds seed data OUTSIDE a builder\n// callback — e.g. unit tests exercising a composed seed fragment directly.\nexport { file, isFileToken, isRef, ref } from './refs'\n\n// Run the seed from a script or test (the `payload seed` command and endpoint use this)\nexport { seed } from './engine/run'\n"],"names":["seedPlugin","defineSeed","file","isFileToken","isRef","ref","seed"],"mappings":"AAAA,aAAa;AACb,SAASA,UAAU,QAAQ,cAAU;AAGrC,iGAAiG;AACjG,2FAA2F;AAC3F,6FAA6F;AAC7F,SAASC,UAAU,QAAQ,kBAAc;AAWzC,sFAAsF;AACtF,2EAA2E;AAC3E,SAASC,IAAI,EAAEC,WAAW,EAAEC,KAAK,EAAEC,GAAG,QAAQ,YAAQ;AAEtD,wFAAwF;AACxF,SAASC,IAAI,QAAQ,kBAAc"}
@@ -0,0 +1,29 @@
1
+ import type { CollectionSlug } from 'payload';
2
+ import type { SeedDefinition } from './types';
3
+ export interface SeedPluginOptions {
4
+ /** The seed definitions (from `defineSeed`). They feed both the
5
+ * seed run and the typed `SeedRegistry` injected into `payload-types.ts`. */
6
+ definitions?: SeedDefinition[];
7
+ /** The assets root where `_file` source files live, relative to the project root (default
8
+ * `assets`). A file is looked up under its per-collection subdir (see {@link assetSubDirs},
9
+ * defaulting to the collection slug) and then the root — the same for native uploads and
10
+ * `custom.seedAsset` collections. */
11
+ assetsDir?: string;
12
+ /** Per-collection subdirectory (under `assetsDir`) for a native upload collection's `_file`
13
+ * source files. Defaults to the collection slug — `media` resolves under `<assetsDir>/media/` —
14
+ * so name a folder after the collection and it just works. Set an entry to use a different folder
15
+ * name, e.g. `{ media: 'images' }`. A `_file` name may also include a relative subpath under the
16
+ * resolved folder (`file('portraits/jane.jpg')`) to subdivide further. */
17
+ assetSubDirs?: Partial<Record<CollectionSlug, string>>;
18
+ /** Show the "Seed your database" button in the admin header. Default: false. */
19
+ adminButton?: boolean;
20
+ }
21
+ /** Options with defaults applied (internal). */
22
+ export interface ResolvedSeedOptions {
23
+ definitions?: SeedDefinition[];
24
+ assetsDir: string;
25
+ assetSubDirs: Partial<Record<string, string>>;
26
+ adminButton: boolean;
27
+ }
28
+ export declare function resolveOptions(options?: SeedPluginOptions): ResolvedSeedOptions;
29
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C,MAAM,WAAW,iBAAiB;IAChC;kFAC8E;IAC9E,WAAW,CAAC,EAAE,cAAc,EAAE,CAAA;IAC9B;;;0CAGsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;+EAI2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAA;IACtD,gFAAgF;IAChF,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,gDAAgD;AAChD,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,cAAc,EAAE,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC7C,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,iBAAsB,GAAG,mBAAmB,CAOnF"}
@@ -0,0 +1,10 @@
1
+ export function resolveOptions(options = {}) {
2
+ return {
3
+ definitions: options.definitions,
4
+ assetsDir: options.assetsDir ?? 'assets',
5
+ assetSubDirs: options.assetSubDirs ?? {},
6
+ adminButton: options.adminButton ?? false
7
+ };
8
+ }
9
+
10
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/options.ts"],"sourcesContent":["import type { CollectionSlug } from 'payload'\nimport type { SeedDefinition } from './types'\n\nexport interface SeedPluginOptions {\n /** The seed definitions (from `defineSeed`). They feed both the\n * seed run and the typed `SeedRegistry` injected into `payload-types.ts`. */\n definitions?: SeedDefinition[]\n /** The assets root where `_file` source files live, relative to the project root (default\n * `assets`). A file is looked up under its per-collection subdir (see {@link assetSubDirs},\n * defaulting to the collection slug) and then the root — the same for native uploads and\n * `custom.seedAsset` collections. */\n assetsDir?: string\n /** Per-collection subdirectory (under `assetsDir`) for a native upload collection's `_file`\n * source files. Defaults to the collection slug — `media` resolves under `<assetsDir>/media/` —\n * so name a folder after the collection and it just works. Set an entry to use a different folder\n * name, e.g. `{ media: 'images' }`. A `_file` name may also include a relative subpath under the\n * resolved folder (`file('portraits/jane.jpg')`) to subdivide further. */\n assetSubDirs?: Partial<Record<CollectionSlug, string>>\n /** Show the \"Seed your database\" button in the admin header. Default: false. */\n adminButton?: boolean\n}\n\n/** Options with defaults applied (internal). */\nexport interface ResolvedSeedOptions {\n definitions?: SeedDefinition[]\n assetsDir: string\n assetSubDirs: Partial<Record<string, string>>\n adminButton: boolean\n}\n\nexport function resolveOptions(options: SeedPluginOptions = {}): ResolvedSeedOptions {\n return {\n definitions: options.definitions,\n assetsDir: options.assetsDir ?? 'assets',\n assetSubDirs: options.assetSubDirs ?? {},\n adminButton: options.adminButton ?? false,\n }\n}\n"],"names":["resolveOptions","options","definitions","assetsDir","assetSubDirs","adminButton"],"mappings":"AA8BA,OAAO,SAASA,eAAeC,UAA6B,CAAC,CAAC;IAC5D,OAAO;QACLC,aAAaD,QAAQC,WAAW;QAChCC,WAAWF,QAAQE,SAAS,IAAI;QAChCC,cAAcH,QAAQG,YAAY,IAAI,CAAC;QACvCC,aAAaJ,QAAQI,WAAW,IAAI;IACtC;AACF"}
@@ -0,0 +1,14 @@
1
+ import type { Plugin } from 'payload';
2
+ import { type SeedPluginOptions } from './options';
3
+ /**
4
+ * The seed plugin. Pass your seed `definitions`; it wires up the rest so a project authors
5
+ * no seed plumbing:
6
+ * - `payload seed` — runs the seed (behind the `ENABLE_SEED` guard).
7
+ * - `POST /api/seed` + the optional admin button — the in-app way to run it.
8
+ * - typed refs — injects the `SeedRegistry` into `payload-types.ts` via Payload's
9
+ * `typescript.postProcess`, so `ref()` keys are checked. Rides `generate:types`.
10
+ *
11
+ * seedPlugin({ definitions: [assets, services, posts], adminButton: true })
12
+ */
13
+ export declare function seedPlugin(options?: SeedPluginOptions): Plugin;
14
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAU,MAAM,EAAE,MAAM,SAAS,CAAA;AAE7C,OAAO,EAAE,KAAK,iBAAiB,EAAkB,MAAM,WAAW,CAAA;AAWlE;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAkClE"}
package/dist/plugin.js ADDED
@@ -0,0 +1,73 @@
1
+ import { dirname, resolve } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { createSeedEndpoint } from "./endpoint.js";
4
+ import { resolveOptions } from "./options.js";
5
+ import { buildSeedRegistry } from "./typegen.js";
6
+ /** Absolute path to a bundled bin script, resolving the src→dist swap from this module's
7
+ * own location (so it works both in-workspace and when published). */ function binScriptPath(name) {
8
+ const here = fileURLToPath(import.meta.url);
9
+ const ext = here.endsWith('.ts') ? 'ts' : 'js';
10
+ return resolve(dirname(here), 'bin', `${name}.${ext}`);
11
+ }
12
+ /**
13
+ * The seed plugin. Pass your seed `definitions`; it wires up the rest so a project authors
14
+ * no seed plumbing:
15
+ * - `payload seed` — runs the seed (behind the `ENABLE_SEED` guard).
16
+ * - `POST /api/seed` + the optional admin button — the in-app way to run it.
17
+ * - typed refs — injects the `SeedRegistry` into `payload-types.ts` via Payload's
18
+ * `typescript.postProcess`, so `ref()` keys are checked. Rides `generate:types`.
19
+ *
20
+ * seedPlugin({ definitions: [assets, services, posts], adminButton: true })
21
+ */ export function seedPlugin(options = {}) {
22
+ const resolved = resolveOptions(options);
23
+ return (incomingConfig)=>{
24
+ const config = {
25
+ ...incomingConfig,
26
+ bin: [
27
+ ...incomingConfig.bin ?? [],
28
+ {
29
+ key: 'seed',
30
+ scriptPath: binScriptPath('seed')
31
+ }
32
+ ],
33
+ custom: {
34
+ ...incomingConfig.custom,
35
+ payloadSeed: {
36
+ options
37
+ }
38
+ },
39
+ endpoints: [
40
+ ...incomingConfig.endpoints ?? [],
41
+ createSeedEndpoint(resolved)
42
+ ]
43
+ };
44
+ // Inject the typed ref registry into `payload-types.ts` during type generation, from the
45
+ // in-memory definitions. Skipped when none are passed (nothing to derive types from).
46
+ if (resolved.definitions?.length) {
47
+ const definitions = resolved.definitions;
48
+ config.typescript = {
49
+ ...config.typescript,
50
+ postProcess: [
51
+ ...config.typescript?.postProcess ?? [],
52
+ ({ compiledTypes })=>`${compiledTypes}\n\n${buildSeedRegistry(definitions)}\n`
53
+ ]
54
+ };
55
+ }
56
+ if (resolved.adminButton) {
57
+ const components = config.admin?.components ?? {};
58
+ config.admin = {
59
+ ...config.admin,
60
+ components: {
61
+ ...components,
62
+ actions: [
63
+ ...components.actions ?? [],
64
+ '@pro-laico/payload-seed/components/SeedButton#SeedButton'
65
+ ]
66
+ }
67
+ };
68
+ }
69
+ return config;
70
+ };
71
+ }
72
+
73
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { Config, Plugin } from 'payload'\nimport { createSeedEndpoint } from './endpoint'\nimport { type SeedPluginOptions, resolveOptions } from './options'\nimport { buildSeedRegistry } from './typegen'\n\n/** Absolute path to a bundled bin script, resolving the src→dist swap from this module's\n * own location (so it works both in-workspace and when published). */\nfunction binScriptPath(name: string): string {\n const here = fileURLToPath(import.meta.url)\n const ext = here.endsWith('.ts') ? 'ts' : 'js'\n return resolve(dirname(here), 'bin', `${name}.${ext}`)\n}\n\n/**\n * The seed plugin. Pass your seed `definitions`; it wires up the rest so a project authors\n * no seed plumbing:\n * - `payload seed` — runs the seed (behind the `ENABLE_SEED` guard).\n * - `POST /api/seed` + the optional admin button — the in-app way to run it.\n * - typed refs — injects the `SeedRegistry` into `payload-types.ts` via Payload's\n * `typescript.postProcess`, so `ref()` keys are checked. Rides `generate:types`.\n *\n * seedPlugin({ definitions: [assets, services, posts], adminButton: true })\n */\nexport function seedPlugin(options: SeedPluginOptions = {}): Plugin {\n const resolved = resolveOptions(options)\n\n return (incomingConfig: Config): Config => {\n const config: Config = {\n ...incomingConfig,\n bin: [...(incomingConfig.bin ?? []), { key: 'seed', scriptPath: binScriptPath('seed') }],\n custom: { ...incomingConfig.custom, payloadSeed: { options } },\n endpoints: [...(incomingConfig.endpoints ?? []), createSeedEndpoint(resolved)],\n }\n\n // Inject the typed ref registry into `payload-types.ts` during type generation, from the\n // in-memory definitions. Skipped when none are passed (nothing to derive types from).\n if (resolved.definitions?.length) {\n const definitions = resolved.definitions\n config.typescript = {\n ...config.typescript,\n postProcess: [\n ...(config.typescript?.postProcess ?? []),\n ({ compiledTypes }) => `${compiledTypes}\\n\\n${buildSeedRegistry(definitions)}\\n`,\n ],\n }\n }\n\n if (resolved.adminButton) {\n const components = config.admin?.components ?? {}\n config.admin = {\n ...config.admin,\n components: { ...components, actions: [...(components.actions ?? []), '@pro-laico/payload-seed/components/SeedButton#SeedButton'] },\n }\n }\n\n return config\n }\n}\n"],"names":["dirname","resolve","fileURLToPath","createSeedEndpoint","resolveOptions","buildSeedRegistry","binScriptPath","name","here","url","ext","endsWith","seedPlugin","options","resolved","incomingConfig","config","bin","key","scriptPath","custom","payloadSeed","endpoints","definitions","length","typescript","postProcess","compiledTypes","adminButton","components","admin","actions"],"mappings":"AAAA,SAASA,OAAO,EAAEC,OAAO,QAAQ,YAAW;AAC5C,SAASC,aAAa,QAAQ,WAAU;AAExC,SAASC,kBAAkB,QAAQ,gBAAY;AAC/C,SAAiCC,cAAc,QAAQ,eAAW;AAClE,SAASC,iBAAiB,QAAQ,eAAW;AAE7C;qEACqE,GACrE,SAASC,cAAcC,IAAY;IACjC,MAAMC,OAAON,cAAc,YAAYO,GAAG;IAC1C,MAAMC,MAAMF,KAAKG,QAAQ,CAAC,SAAS,OAAO;IAC1C,OAAOV,QAAQD,QAAQQ,OAAO,OAAO,GAAGD,KAAK,CAAC,EAAEG,KAAK;AACvD;AAEA;;;;;;;;;CASC,GACD,OAAO,SAASE,WAAWC,UAA6B,CAAC,CAAC;IACxD,MAAMC,WAAWV,eAAeS;IAEhC,OAAO,CAACE;QACN,MAAMC,SAAiB;YACrB,GAAGD,cAAc;YACjBE,KAAK;mBAAKF,eAAeE,GAAG,IAAI,EAAE;gBAAG;oBAAEC,KAAK;oBAAQC,YAAYb,cAAc;gBAAQ;aAAE;YACxFc,QAAQ;gBAAE,GAAGL,eAAeK,MAAM;gBAAEC,aAAa;oBAAER;gBAAQ;YAAE;YAC7DS,WAAW;mBAAKP,eAAeO,SAAS,IAAI,EAAE;gBAAGnB,mBAAmBW;aAAU;QAChF;QAEA,yFAAyF;QACzF,sFAAsF;QACtF,IAAIA,SAASS,WAAW,EAAEC,QAAQ;YAChC,MAAMD,cAAcT,SAASS,WAAW;YACxCP,OAAOS,UAAU,GAAG;gBAClB,GAAGT,OAAOS,UAAU;gBACpBC,aAAa;uBACPV,OAAOS,UAAU,EAAEC,eAAe,EAAE;oBACxC,CAAC,EAAEC,aAAa,EAAE,GAAK,GAAGA,cAAc,IAAI,EAAEtB,kBAAkBkB,aAAa,EAAE,CAAC;iBACjF;YACH;QACF;QAEA,IAAIT,SAASc,WAAW,EAAE;YACxB,MAAMC,aAAab,OAAOc,KAAK,EAAED,cAAc,CAAC;YAChDb,OAAOc,KAAK,GAAG;gBACb,GAAGd,OAAOc,KAAK;gBACfD,YAAY;oBAAE,GAAGA,UAAU;oBAAEE,SAAS;2BAAKF,WAAWE,OAAO,IAAI,EAAE;wBAAG;qBAA2D;gBAAC;YACpI;QACF;QAEA,OAAOf;IACT;AACF"}
package/dist/refs.d.ts ADDED
@@ -0,0 +1,56 @@
1
+ import type { RegistryCollectionSlug, RegistryCollections, RegistryKey } from './registry';
2
+ /**
3
+ * A typed reference to another seeded document, used in place of a raw id inside seed
4
+ * data. The engine resolves it to the created doc's id at create time and records a
5
+ * dependency edge (dependent → dependency) for the topological sort and graph. A ref
6
+ * is the ONLY way to point at another doc — you can't fabricate an id — which is what
7
+ * makes the dependency graph complete and tamper-resistant.
8
+ */
9
+ export interface Ref<C extends RegistryCollectionSlug = RegistryCollectionSlug> {
10
+ readonly __seedRef: 'doc';
11
+ readonly collection: C;
12
+ readonly key: RegistryKey<C>;
13
+ }
14
+ /**
15
+ * A file attached to a seeded upload/provider doc via its `_file` meta-key. Carries a source
16
+ * filename (resolved under the assets dir at seed time) plus optional provider-specific options.
17
+ * How the file is delivered depends on the doc's collection:
18
+ * - an **upload collection** → the bytes are read and passed as the created doc's upload.
19
+ * - a registered **provider collection** (e.g. Mux, fonts) → the resolved path + options are
20
+ * handed to the collection's ingest hook via its source field.
21
+ */
22
+ export interface FileToken {
23
+ readonly __seedRef: 'file';
24
+ /** Source filename, resolved under the assets dir (native: searched subdirs; provider: its subdir). */
25
+ readonly name: string;
26
+ /** Provider-specific ingest options (e.g. a font `weight`), merged into the provider source field.
27
+ * Ignored for native uploads. */
28
+ readonly options: Record<string, unknown>;
29
+ }
30
+ /** Any edge-creating reference (drives the dependency graph). Only doc refs create edges. */
31
+ export type AnyRef = Ref;
32
+ /** Any seed token that may appear in record data. */
33
+ export type AnyToken = Ref | FileToken;
34
+ /**
35
+ * Reference a seeded document by collection slug and local `_key`. Type-checked against
36
+ * the generated {@link SeedRegistry} — once codegen has run, an unknown or removed key
37
+ * is a TS error at every use site.
38
+ *
39
+ * relatedService: ref('services', 'consulting')
40
+ */
41
+ export declare function ref<C extends RegistryCollectionSlug>(collection: C, key: RegistryCollections[C] & string): Ref<C>;
42
+ /**
43
+ * Attach a source file to a seeded doc via its `_file` meta-key. The engine resolves the file
44
+ * under the assets dir and — depending on the doc's collection — either uploads the bytes
45
+ * (native upload collection) or hands the path to the collection's ingest hook (provider).
46
+ *
47
+ * { _key: 'lighthouse', _file: file('lighthouse.png'), alt: 'A lighthouse' } // native upload
48
+ * { _key: 'intro', _file: file('intro.mp4'), title: 'Intro' } // Mux provider
49
+ * { _key: 'inter', _file: file('inter.woff2', { weight: '400' }), family: 'sans' } // fonts provider
50
+ */
51
+ export declare function file(name: string, options?: Record<string, unknown>): FileToken;
52
+ export declare function isRef(value: unknown): value is Ref;
53
+ export declare function isFileToken(value: unknown): value is FileToken;
54
+ /** Any seed token (doc reference or file). */
55
+ export declare function isAnyToken(value: unknown): value is AnyToken;
56
+ //# sourceMappingURL=refs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../src/refs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE1F;;;;;;GAMG;AACH,MAAM,WAAW,GAAG,CAAC,CAAC,SAAS,sBAAsB,GAAG,sBAAsB;IAC5E,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;IACtB,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;CAC7B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,uGAAuG;IACvG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;sCACkC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC1C;AAED,6FAA6F;AAC7F,MAAM,MAAM,MAAM,GAAG,GAAG,CAAA;AAExB,qDAAqD;AACrD,MAAM,MAAM,QAAQ,GAAG,GAAG,GAAG,SAAS,CAAA;AAEtC;;;;;;GAMG;AACH,wBAAgB,GAAG,CAAC,CAAC,SAAS,sBAAsB,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAEjH;AAED;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,SAAS,CAEnF;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,GAAG,CAElD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAE9D;AAED,8CAA8C;AAC9C,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D"}
package/dist/refs.js ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Reference a seeded document by collection slug and local `_key`. Type-checked against
3
+ * the generated {@link SeedRegistry} — once codegen has run, an unknown or removed key
4
+ * is a TS error at every use site.
5
+ *
6
+ * relatedService: ref('services', 'consulting')
7
+ */ export function ref(collection, key) {
8
+ return {
9
+ __seedRef: 'doc',
10
+ collection,
11
+ key: key
12
+ };
13
+ }
14
+ /**
15
+ * Attach a source file to a seeded doc via its `_file` meta-key. The engine resolves the file
16
+ * under the assets dir and — depending on the doc's collection — either uploads the bytes
17
+ * (native upload collection) or hands the path to the collection's ingest hook (provider).
18
+ *
19
+ * { _key: 'lighthouse', _file: file('lighthouse.png'), alt: 'A lighthouse' } // native upload
20
+ * { _key: 'intro', _file: file('intro.mp4'), title: 'Intro' } // Mux provider
21
+ * { _key: 'inter', _file: file('inter.woff2', { weight: '400' }), family: 'sans' } // fonts provider
22
+ */ export function file(name, options = {}) {
23
+ return {
24
+ __seedRef: 'file',
25
+ name,
26
+ options
27
+ };
28
+ }
29
+ export function isRef(value) {
30
+ return typeof value === 'object' && value !== null && value.__seedRef === 'doc';
31
+ }
32
+ export function isFileToken(value) {
33
+ return typeof value === 'object' && value !== null && value.__seedRef === 'file';
34
+ }
35
+ /** Any seed token (doc reference or file). */ export function isAnyToken(value) {
36
+ return isRef(value) || isFileToken(value);
37
+ }
38
+
39
+ //# sourceMappingURL=refs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/refs.ts"],"sourcesContent":["import type { RegistryCollectionSlug, RegistryCollections, RegistryKey } from './registry'\n\n/**\n * A typed reference to another seeded document, used in place of a raw id inside seed\n * data. The engine resolves it to the created doc's id at create time and records a\n * dependency edge (dependent → dependency) for the topological sort and graph. A ref\n * is the ONLY way to point at another doc — you can't fabricate an id — which is what\n * makes the dependency graph complete and tamper-resistant.\n */\nexport interface Ref<C extends RegistryCollectionSlug = RegistryCollectionSlug> {\n readonly __seedRef: 'doc'\n readonly collection: C\n readonly key: RegistryKey<C>\n}\n\n/**\n * A file attached to a seeded upload/provider doc via its `_file` meta-key. Carries a source\n * filename (resolved under the assets dir at seed time) plus optional provider-specific options.\n * How the file is delivered depends on the doc's collection:\n * - an **upload collection** → the bytes are read and passed as the created doc's upload.\n * - a registered **provider collection** (e.g. Mux, fonts) → the resolved path + options are\n * handed to the collection's ingest hook via its source field.\n */\nexport interface FileToken {\n readonly __seedRef: 'file'\n /** Source filename, resolved under the assets dir (native: searched subdirs; provider: its subdir). */\n readonly name: string\n /** Provider-specific ingest options (e.g. a font `weight`), merged into the provider source field.\n * Ignored for native uploads. */\n readonly options: Record<string, unknown>\n}\n\n/** Any edge-creating reference (drives the dependency graph). Only doc refs create edges. */\nexport type AnyRef = Ref\n\n/** Any seed token that may appear in record data. */\nexport type AnyToken = Ref | FileToken\n\n/**\n * Reference a seeded document by collection slug and local `_key`. Type-checked against\n * the generated {@link SeedRegistry} — once codegen has run, an unknown or removed key\n * is a TS error at every use site.\n *\n * relatedService: ref('services', 'consulting')\n */\nexport function ref<C extends RegistryCollectionSlug>(collection: C, key: RegistryCollections[C] & string): Ref<C> {\n return { __seedRef: 'doc', collection, key: key as RegistryKey<C> }\n}\n\n/**\n * Attach a source file to a seeded doc via its `_file` meta-key. The engine resolves the file\n * under the assets dir and — depending on the doc's collection — either uploads the bytes\n * (native upload collection) or hands the path to the collection's ingest hook (provider).\n *\n * { _key: 'lighthouse', _file: file('lighthouse.png'), alt: 'A lighthouse' } // native upload\n * { _key: 'intro', _file: file('intro.mp4'), title: 'Intro' } // Mux provider\n * { _key: 'inter', _file: file('inter.woff2', { weight: '400' }), family: 'sans' } // fonts provider\n */\nexport function file(name: string, options: Record<string, unknown> = {}): FileToken {\n return { __seedRef: 'file', name, options }\n}\n\nexport function isRef(value: unknown): value is Ref {\n return typeof value === 'object' && value !== null && (value as { __seedRef?: unknown }).__seedRef === 'doc'\n}\n\nexport function isFileToken(value: unknown): value is FileToken {\n return typeof value === 'object' && value !== null && (value as { __seedRef?: unknown }).__seedRef === 'file'\n}\n\n/** Any seed token (doc reference or file). */\nexport function isAnyToken(value: unknown): value is AnyToken {\n return isRef(value) || isFileToken(value)\n}\n"],"names":["ref","collection","key","__seedRef","file","name","options","isRef","value","isFileToken","isAnyToken"],"mappings":"AAsCA;;;;;;CAMC,GACD,OAAO,SAASA,IAAsCC,UAAa,EAAEC,GAAoC;IACvG,OAAO;QAAEC,WAAW;QAAOF;QAAYC,KAAKA;IAAsB;AACpE;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASE,KAAKC,IAAY,EAAEC,UAAmC,CAAC,CAAC;IACtE,OAAO;QAAEH,WAAW;QAAQE;QAAMC;IAAQ;AAC5C;AAEA,OAAO,SAASC,MAAMC,KAAc;IAClC,OAAO,OAAOA,UAAU,YAAYA,UAAU,QAAQ,AAACA,MAAkCL,SAAS,KAAK;AACzG;AAEA,OAAO,SAASM,YAAYD,KAAc;IACxC,OAAO,OAAOA,UAAU,YAAYA,UAAU,QAAQ,AAACA,MAAkCL,SAAS,KAAK;AACzG;AAEA,4CAA4C,GAC5C,OAAO,SAASO,WAAWF,KAAc;IACvC,OAAOD,MAAMC,UAAUC,YAAYD;AACrC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The cross-file type bridge. The set of valid reference keys is materialized into types by
3
+ * the plugin, which injects an augmentation of this interface into the project's
4
+ * `payload-types.ts` during `payload generate:types` (via `typescript.postProcess`):
5
+ *
6
+ * declare module '@pro-laico/payload-seed' {
7
+ * interface SeedRegistry {
8
+ * collections: { services: 'consulting' | 'implementation'; posts: 'launch' }
9
+ * globals: 'header' | 'footer'
10
+ * }
11
+ * }
12
+ *
13
+ * Once augmented, `ref()` keys are checked against these unions — remove a seeded item's
14
+ * `_key` and every reference to it becomes a TS error. Before types are generated (interface
15
+ * empty), the resolvers below fall back to permissive `string` keys, so refs are
16
+ * runtime-validated only. Progressive: safe without it, fully safe with it.
17
+ */
18
+ export interface SeedRegistry {
19
+ }
20
+ /** Resolve `SeedRegistry[K]` if augmented, else the permissive default `D`. */
21
+ type Resolve<K extends string, D> = K extends keyof SeedRegistry ? SeedRegistry[K] : D;
22
+ /** Map of collection slug → union of that collection's declared `_key`s. */
23
+ export type RegistryCollections = Resolve<'collections', Record<string, string>>;
24
+ /** Slugs that have at least one seeded doc (the keys of {@link RegistryCollections}). */
25
+ export type RegistryCollectionSlug = keyof RegistryCollections & string;
26
+ /** Valid ref keys for a given collection slug. */
27
+ export type RegistryKey<C extends RegistryCollectionSlug> = RegistryCollections[C] & string;
28
+ /** Union of declared global slugs. */
29
+ export type RegistryGlobal = Resolve<'globals', string>;
30
+ export {};
31
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,YAAY;CAAG;AAEhC,+EAA+E;AAC/E,KAAK,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,IAAI,CAAC,SAAS,MAAM,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;AAEtF,4EAA4E;AAC5E,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAEhF,yFAAyF;AACzF,MAAM,MAAM,sBAAsB,GAAG,MAAM,mBAAmB,GAAG,MAAM,CAAA;AAEvE,kDAAkD;AAClD,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,sBAAsB,IAAI,mBAAmB,CAAC,CAAC,CAAC,GAAG,MAAM,CAAA;AAE3F,sCAAsC;AACtC,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The cross-file type bridge. The set of valid reference keys is materialized into types by
3
+ * the plugin, which injects an augmentation of this interface into the project's
4
+ * `payload-types.ts` during `payload generate:types` (via `typescript.postProcess`):
5
+ *
6
+ * declare module '@pro-laico/payload-seed' {
7
+ * interface SeedRegistry {
8
+ * collections: { services: 'consulting' | 'implementation'; posts: 'launch' }
9
+ * globals: 'header' | 'footer'
10
+ * }
11
+ * }
12
+ *
13
+ * Once augmented, `ref()` keys are checked against these unions — remove a seeded item's
14
+ * `_key` and every reference to it becomes a TS error. Before types are generated (interface
15
+ * empty), the resolvers below fall back to permissive `string` keys, so refs are
16
+ * runtime-validated only. Progressive: safe without it, fully safe with it.
17
+ */ // Intentionally empty — augmented in the project's payload-types.ts during generate:types.
18
+ /** Union of declared global slugs. */ export { };
19
+
20
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/registry.ts"],"sourcesContent":["/**\n * The cross-file type bridge. The set of valid reference keys is materialized into types by\n * the plugin, which injects an augmentation of this interface into the project's\n * `payload-types.ts` during `payload generate:types` (via `typescript.postProcess`):\n *\n * declare module '@pro-laico/payload-seed' {\n * interface SeedRegistry {\n * collections: { services: 'consulting' | 'implementation'; posts: 'launch' }\n * globals: 'header' | 'footer'\n * }\n * }\n *\n * Once augmented, `ref()` keys are checked against these unions — remove a seeded item's\n * `_key` and every reference to it becomes a TS error. Before types are generated (interface\n * empty), the resolvers below fall back to permissive `string` keys, so refs are\n * runtime-validated only. Progressive: safe without it, fully safe with it.\n */\n// Intentionally empty — augmented in the project's payload-types.ts during generate:types.\nexport interface SeedRegistry {}\n\n/** Resolve `SeedRegistry[K]` if augmented, else the permissive default `D`. */\ntype Resolve<K extends string, D> = K extends keyof SeedRegistry ? SeedRegistry[K] : D\n\n/** Map of collection slug → union of that collection's declared `_key`s. */\nexport type RegistryCollections = Resolve<'collections', Record<string, string>>\n\n/** Slugs that have at least one seeded doc (the keys of {@link RegistryCollections}). */\nexport type RegistryCollectionSlug = keyof RegistryCollections & string\n\n/** Valid ref keys for a given collection slug. */\nexport type RegistryKey<C extends RegistryCollectionSlug> = RegistryCollections[C] & string\n\n/** Union of declared global slugs. */\nexport type RegistryGlobal = Resolve<'globals', string>\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;CAgBC,GACD,2FAA2F;AAe3F,oCAAoC,GACpC,WAAuD"}
@@ -0,0 +1,13 @@
1
+ import type { SeedDefinition } from './types';
2
+ /** Module name whose `SeedRegistry` interface the generated augmentation targets. */
3
+ export declare const SEED_PACKAGE = "@pro-laico/payload-seed";
4
+ /**
5
+ * Build the `declare module '@pro-laico/payload-seed' { interface SeedRegistry … }`
6
+ * augmentation from the in-memory seed definitions — collection `_key`s and global slugs. The
7
+ * plugin appends this to Payload's generated types via `typescript.postProcess`, so `ref()` keys
8
+ * are type-checked in `payload-types.ts` (rename/remove a seeded item, regenerate, and every
9
+ * reference errors). No filesystem access — the keys come from the same definition data the engine
10
+ * seeds.
11
+ */
12
+ export declare function buildSeedRegistry(definitions: SeedDefinition[], packageName?: string): string;
13
+ //# sourceMappingURL=typegen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typegen.d.ts","sourceRoot":"","sources":["../src/typegen.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C,qFAAqF;AACrF,eAAO,MAAM,YAAY,4BAA4B,CAAA;AAKrD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,EAAE,WAAW,GAAE,MAAqB,GAAG,MAAM,CAiB3G"}
@@ -0,0 +1,40 @@
1
+ import { file, ref } from "./refs.js";
2
+ /** Module name whose `SeedRegistry` interface the generated augmentation targets. */ export const SEED_PACKAGE = '@pro-laico/payload-seed';
3
+ const tokens = {
4
+ ref,
5
+ file
6
+ };
7
+ const union = (values)=>values.length ? values.map((v)=>`'${v}'`).join(' | ') : 'never';
8
+ /**
9
+ * Build the `declare module '@pro-laico/payload-seed' { interface SeedRegistry … }`
10
+ * augmentation from the in-memory seed definitions — collection `_key`s and global slugs. The
11
+ * plugin appends this to Payload's generated types via `typescript.postProcess`, so `ref()` keys
12
+ * are type-checked in `payload-types.ts` (rename/remove a seeded item, regenerate, and every
13
+ * reference errors). No filesystem access — the keys come from the same definition data the engine
14
+ * seeds.
15
+ */ export function buildSeedRegistry(definitions, packageName = SEED_PACKAGE) {
16
+ const collections = {};
17
+ const globals = new Set();
18
+ for (const def of definitions){
19
+ if (def.kind === 'global') globals.add(def.slug);
20
+ else if (def.kind === 'collection') {
21
+ collections[def.slug] ??= new Set();
22
+ const set = collections[def.slug];
23
+ for (const rec of def.build(tokens))set?.add(rec._key);
24
+ }
25
+ }
26
+ const lines = [
27
+ `declare module '${packageName}' {`,
28
+ ' interface SeedRegistry {',
29
+ ' collections: {'
30
+ ];
31
+ for (const slug of Object.keys(collections).sort())lines.push(` '${slug}': ${union([
32
+ ...collections[slug] ?? []
33
+ ].sort())}`);
34
+ lines.push(' }', ` globals: ${union([
35
+ ...globals
36
+ ].sort())}`, ' }', '}');
37
+ return lines.join('\n');
38
+ }
39
+
40
+ //# sourceMappingURL=typegen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/typegen.ts"],"sourcesContent":["import { file, ref } from './refs'\nimport type { SeedDefinition } from './types'\n\n/** Module name whose `SeedRegistry` interface the generated augmentation targets. */\nexport const SEED_PACKAGE = '@pro-laico/payload-seed'\n\nconst tokens = { ref, file }\nconst union = (values: string[]): string => (values.length ? values.map((v) => `'${v}'`).join(' | ') : 'never')\n\n/**\n * Build the `declare module '@pro-laico/payload-seed' { interface SeedRegistry … }`\n * augmentation from the in-memory seed definitions — collection `_key`s and global slugs. The\n * plugin appends this to Payload's generated types via `typescript.postProcess`, so `ref()` keys\n * are type-checked in `payload-types.ts` (rename/remove a seeded item, regenerate, and every\n * reference errors). No filesystem access — the keys come from the same definition data the engine\n * seeds.\n */\nexport function buildSeedRegistry(definitions: SeedDefinition[], packageName: string = SEED_PACKAGE): string {\n const collections: Record<string, Set<string>> = {}\n const globals = new Set<string>()\n\n for (const def of definitions) {\n if (def.kind === 'global') globals.add(def.slug)\n else if (def.kind === 'collection') {\n collections[def.slug] ??= new Set()\n const set = collections[def.slug]\n for (const rec of def.build(tokens)) set?.add((rec as { _key: string })._key)\n }\n }\n\n const lines = [`declare module '${packageName}' {`, ' interface SeedRegistry {', ' collections: {']\n for (const slug of Object.keys(collections).sort()) lines.push(` '${slug}': ${union([...(collections[slug] ?? [])].sort())}`)\n lines.push(' }', ` globals: ${union([...globals].sort())}`, ' }', '}')\n return lines.join('\\n')\n}\n"],"names":["file","ref","SEED_PACKAGE","tokens","union","values","length","map","v","join","buildSeedRegistry","definitions","packageName","collections","globals","Set","def","kind","add","slug","set","rec","build","_key","lines","Object","keys","sort","push"],"mappings":"AAAA,SAASA,IAAI,EAAEC,GAAG,QAAQ,YAAQ;AAGlC,mFAAmF,GACnF,OAAO,MAAMC,eAAe,0BAAyB;AAErD,MAAMC,SAAS;IAAEF;IAAKD;AAAK;AAC3B,MAAMI,QAAQ,CAACC,SAA8BA,OAAOC,MAAM,GAAGD,OAAOE,GAAG,CAAC,CAACC,IAAM,CAAC,CAAC,EAAEA,EAAE,CAAC,CAAC,EAAEC,IAAI,CAAC,SAAS;AAEvG;;;;;;;CAOC,GACD,OAAO,SAASC,kBAAkBC,WAA6B,EAAEC,cAAsBV,YAAY;IACjG,MAAMW,cAA2C,CAAC;IAClD,MAAMC,UAAU,IAAIC;IAEpB,KAAK,MAAMC,OAAOL,YAAa;QAC7B,IAAIK,IAAIC,IAAI,KAAK,UAAUH,QAAQI,GAAG,CAACF,IAAIG,IAAI;aAC1C,IAAIH,IAAIC,IAAI,KAAK,cAAc;YAClCJ,WAAW,CAACG,IAAIG,IAAI,CAAC,KAAK,IAAIJ;YAC9B,MAAMK,MAAMP,WAAW,CAACG,IAAIG,IAAI,CAAC;YACjC,KAAK,MAAME,OAAOL,IAAIM,KAAK,CAACnB,QAASiB,KAAKF,IAAI,AAACG,IAAyBE,IAAI;QAC9E;IACF;IAEA,MAAMC,QAAQ;QAAC,CAAC,gBAAgB,EAAEZ,YAAY,GAAG,CAAC;QAAE;QAA8B;KAAqB;IACvG,KAAK,MAAMO,QAAQM,OAAOC,IAAI,CAACb,aAAac,IAAI,GAAIH,MAAMI,IAAI,CAAC,CAAC,OAAO,EAAET,KAAK,GAAG,EAAEf,MAAM;WAAKS,WAAW,CAACM,KAAK,IAAI,EAAE;KAAE,CAACQ,IAAI,KAAK;IACjIH,MAAMI,IAAI,CAAC,SAAS,CAAC,aAAa,EAAExB,MAAM;WAAIU;KAAQ,CAACa,IAAI,KAAK,EAAE,OAAO;IACzE,OAAOH,MAAMf,IAAI,CAAC;AACpB"}