@onlyworlds/sdk 3.1.0 → 4.0.0-alpha.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/dist/index.mjs DELETED
@@ -1,1576 +0,0 @@
1
- // src/types.ts
2
- var ElementType = /* @__PURE__ */ ((ElementType2) => {
3
- ElementType2["Ability"] = "ability";
4
- ElementType2["Character"] = "character";
5
- ElementType2["Collective"] = "collective";
6
- ElementType2["Construct"] = "construct";
7
- ElementType2["Creature"] = "creature";
8
- ElementType2["Event"] = "event";
9
- ElementType2["Family"] = "family";
10
- ElementType2["Institution"] = "institution";
11
- ElementType2["Language"] = "language";
12
- ElementType2["Law"] = "law";
13
- ElementType2["Location"] = "location";
14
- ElementType2["Map"] = "map";
15
- ElementType2["Marker"] = "marker";
16
- ElementType2["Narrative"] = "narrative";
17
- ElementType2["Object"] = "object";
18
- ElementType2["Phenomenon"] = "phenomenon";
19
- ElementType2["Pin"] = "pin";
20
- ElementType2["Relation"] = "relation";
21
- ElementType2["Species"] = "species";
22
- ElementType2["Title"] = "title";
23
- ElementType2["Trait"] = "trait";
24
- ElementType2["Zone"] = "zone";
25
- return ElementType2;
26
- })(ElementType || {});
27
- var ELEMENT_LABELS = {
28
- ["ability" /* Ability */]: "Abilities",
29
- ["character" /* Character */]: "Characters",
30
- ["collective" /* Collective */]: "Collectives",
31
- ["construct" /* Construct */]: "Constructs",
32
- ["creature" /* Creature */]: "Creatures",
33
- ["event" /* Event */]: "Events",
34
- ["family" /* Family */]: "Families",
35
- ["institution" /* Institution */]: "Institutions",
36
- ["language" /* Language */]: "Languages",
37
- ["law" /* Law */]: "Laws",
38
- ["location" /* Location */]: "Locations",
39
- ["map" /* Map */]: "Maps",
40
- ["marker" /* Marker */]: "Markers",
41
- ["narrative" /* Narrative */]: "Narratives",
42
- ["object" /* Object */]: "Objects",
43
- ["phenomenon" /* Phenomenon */]: "Phenomena",
44
- ["pin" /* Pin */]: "Pins",
45
- ["relation" /* Relation */]: "Relations",
46
- ["species" /* Species */]: "Species",
47
- ["title" /* Title */]: "Titles",
48
- ["trait" /* Trait */]: "Traits",
49
- ["zone" /* Zone */]: "Zones"
50
- };
51
- function getElementLabel(elementType) {
52
- return ELEMENT_LABELS[elementType];
53
- }
54
- var ELEMENT_SECTIONS = {
55
- ["ability" /* Ability */]: [
56
- { name: "Mechanics", order: 1, fields: ["activation", "duration", "potency", "range", "effects", "challenges", "talents", "requisites"] },
57
- { name: "World", order: 2, fields: ["prevalence", "tradition", "source", "locus", "instruments", "systems"] }
58
- ],
59
- ["character" /* Character */]: [
60
- { name: "Constitution", order: 1, fields: ["physicality", "mentality", "height", "weight", "species", "traits", "abilities"] },
61
- { name: "Origins", order: 2, fields: ["background", "motivations", "birth_date", "birthplace", "languages"] },
62
- { name: "World", order: 3, fields: ["reputation", "location", "objects", "institutions"] },
63
- { name: "Personality", order: 4, fields: ["charisma", "coercion", "competence", "compassion", "creativity", "courage"] },
64
- { name: "Social", order: 5, fields: ["family", "friends", "rivals"] },
65
- { name: "TTRPG", order: 6, fields: ["level", "hit_points", "STR", "DEX", "CON", "INT", "WIS", "CHA"] }
66
- ],
67
- ["collective" /* Collective */]: [
68
- { name: "Formation", order: 1, fields: ["composition", "count", "formation_date", "operator", "equipment"] },
69
- { name: "Dynamics", order: 2, fields: ["activity", "disposition", "state", "abilities", "symbolism"] },
70
- { name: "World", order: 3, fields: ["species", "characters", "creatures", "phenomena"] }
71
- ],
72
- ["construct" /* Construct */]: [
73
- { name: "Nature", order: 1, fields: ["rationale", "history", "status", "reach", "start_date", "end_date", "founder", "custodian"] },
74
- { name: "Involves", order: 2, fields: ["characters", "objects", "locations", "species", "creatures", "institutions", "traits", "collectives", "zones", "abilities", "phenomena", "languages", "families", "relations", "titles", "constructs", "events", "narratives"] }
75
- ],
76
- ["creature" /* Creature */]: [
77
- { name: "Biology", order: 1, fields: ["appearance", "weight", "height", "species"] },
78
- { name: "Behaviour", order: 2, fields: ["habits", "demeanor", "traits", "abilities", "languages"] },
79
- { name: "World", order: 3, fields: ["status", "birth_date", "location", "zone"] },
80
- { name: "TTRPG", order: 4, fields: ["challenge_rating", "hit_points", "armor_class", "speed", "actions"] }
81
- ],
82
- ["event" /* Event */]: [
83
- { name: "Nature", order: 1, fields: ["history", "challenges", "consequences", "start_date", "end_date", "triggers"] },
84
- { name: "Involves", order: 2, fields: ["characters", "objects", "locations", "species", "creatures", "institutions", "traits", "collectives", "zones", "abilities", "phenomena", "languages", "families", "relations", "titles", "constructs"] }
85
- ],
86
- ["family" /* Family */]: [
87
- { name: "Identity", order: 1, fields: ["spirit", "history", "traditions", "traits", "abilities", "languages", "ancestors"] },
88
- { name: "World", order: 2, fields: ["reputation", "estates", "governs", "heirlooms", "creatures"] }
89
- ],
90
- ["institution" /* Institution */]: [
91
- { name: "Foundation", order: 1, fields: ["doctrine", "founding_date", "parent_institution"] },
92
- { name: "Claims", order: 2, fields: ["zones", "objects", "creatures"] },
93
- { name: "World", order: 3, fields: ["status", "allies", "adversaries", "constructs"] }
94
- ],
95
- ["language" /* Language */]: [
96
- { name: "Structure", order: 1, fields: ["phonology", "grammar", "lexicon", "writing", "classification"] },
97
- { name: "World", order: 2, fields: ["status", "spread", "dialects"] }
98
- ],
99
- ["law" /* Law */]: [
100
- { name: "Code", order: 1, fields: ["declaration", "purpose", "date", "parent_law", "penalties"] },
101
- { name: "World", order: 2, fields: ["author", "locations", "zones", "prohibitions", "adjudicators", "enforcers"] }
102
- ],
103
- ["location" /* Location */]: [
104
- { name: "Setting", order: 1, fields: ["form", "function", "founding_date", "parent_location", "populations"] },
105
- { name: "Politics", order: 2, fields: ["political_climate", "primary_power", "governing_title", "secondary_powers", "zone", "rival", "partner"] },
106
- { name: "World", order: 3, fields: ["customs", "founders", "cults", "delicacies"] },
107
- { name: "Production", order: 4, fields: ["extraction_methods", "extraction_goods", "industry_methods", "industry_goods"] },
108
- { name: "Commerce", order: 5, fields: ["infrastructure", "extraction_markets", "industry_markets", "currencies"] },
109
- { name: "Construction", order: 6, fields: ["architecture", "buildings", "building_methods"] },
110
- { name: "Defense", order: 7, fields: ["defensibility", "elevation", "fighters", "defensive_objects"] }
111
- ],
112
- ["map" /* Map */]: [
113
- { name: "Details", order: 1, fields: ["background_color", "hierarchy", "width", "height", "depth", "parent_map", "location"] }
114
- ],
115
- ["marker" /* Marker */]: [
116
- { name: "Details", order: 1, fields: ["map", "zone", "x", "y", "z", "order"] }
117
- ],
118
- ["narrative" /* Narrative */]: [
119
- { name: "Context", order: 1, fields: ["story", "consequences", "start_date", "end_date", "order", "parent_narrative", "protagonist", "antagonist", "narrator", "conservator"] },
120
- { name: "Involves", order: 2, fields: ["events", "characters", "objects", "locations", "species", "creatures", "institutions", "traits", "collectives", "zones", "abilities", "phenomena", "languages", "families", "relations", "titles", "constructs", "laws"] }
121
- ],
122
- ["object" /* Object */]: [
123
- { name: "Form", order: 1, fields: ["aesthetics", "weight", "amount", "parent_object", "materials", "technology"] },
124
- { name: "Function", order: 2, fields: ["utility", "effects", "abilities", "consumes"] },
125
- { name: "World", order: 3, fields: ["origins", "location", "language", "affinities"] }
126
- ],
127
- ["phenomenon" /* Phenomenon */]: [
128
- { name: "Mechanics", order: 1, fields: ["expression", "effects", "duration", "catalysts", "empowerments"] },
129
- { name: "World", order: 2, fields: ["mythology", "system", "triggers", "wielders", "environments"] }
130
- ],
131
- ["pin" /* Pin */]: [
132
- { name: "Details", order: 1, fields: ["map", "element_type", "element_id", "element", "x", "y", "z"] }
133
- ],
134
- ["relation" /* Relation */]: [
135
- { name: "Nature", order: 1, fields: ["background", "start_date", "end_date", "intensity", "actor", "events"] },
136
- { name: "Involves", order: 2, fields: ["characters", "objects", "locations", "species", "creatures", "institutions", "traits", "collectives", "zones", "abilities", "phenomena", "languages", "families", "relations", "titles", "constructs", "events", "narratives"] }
137
- ],
138
- ["species" /* Species */]: [
139
- { name: "Biology", order: 1, fields: ["appearance", "life_span", "weight", "nourishment", "reproduction", "adaptations"] },
140
- { name: "Psychology", order: 2, fields: ["instincts", "sociality", "temperament", "communication", "aggression", "traits"] },
141
- { name: "World", order: 3, fields: ["role", "parent_species", "locations", "zones", "affinities"] }
142
- ],
143
- ["title" /* Title */]: [
144
- { name: "Mandate", order: 1, fields: ["authority", "eligibility", "grant_date", "revoke_date", "issuer", "body", "superior_title", "holders", "symbols"] },
145
- { name: "World", order: 2, fields: ["status", "history", "characters", "institutions", "families", "zones", "locations", "objects", "constructs", "laws", "collectives", "creatures", "phenomena", "species", "languages"] }
146
- ],
147
- ["trait" /* Trait */]: [
148
- { name: "Qualitative", order: 1, fields: ["social_effects", "physical_effects", "functional_effects", "personality_effects", "behaviour_effects"] },
149
- { name: "Quantitative", order: 2, fields: ["charisma", "coercion", "competence", "compassion", "creativity", "courage"] },
150
- { name: "World", order: 3, fields: ["significance", "anti_trait", "empowered_abilities"] }
151
- ],
152
- ["zone" /* Zone */]: [
153
- { name: "Scope", order: 1, fields: ["role", "start_date", "end_date", "phenomena", "linked_zones"] },
154
- { name: "World", order: 2, fields: ["context", "populations", "titles", "principles"] }
155
- ]
156
- };
157
- function getElementSections(elementType) {
158
- return ELEMENT_SECTIONS[elementType] || [];
159
- }
160
- var ONLYWORLDS_VERSION = "00.30.00";
161
- var ELEMENT_ICONS = {
162
- ["ability" /* Ability */]: "auto_fix_normal",
163
- ["character" /* Character */]: "person",
164
- ["collective" /* Collective */]: "groups_3",
165
- ["construct" /* Construct */]: "api",
166
- ["creature" /* Creature */]: "bug_report",
167
- ["event" /* Event */]: "saved_search",
168
- ["family" /* Family */]: "supervisor_account",
169
- ["institution" /* Institution */]: "business",
170
- ["language" /* Language */]: "edit_road",
171
- ["law" /* Law */]: "gpp_bad",
172
- ["location" /* Location */]: "castle",
173
- ["map" /* Map */]: "map",
174
- ["marker" /* Marker */]: "place",
175
- ["narrative" /* Narrative */]: "menu_book",
176
- ["object" /* Object */]: "webhook",
177
- ["phenomenon" /* Phenomenon */]: "thunderstorm",
178
- ["pin" /* Pin */]: "push_pin",
179
- ["relation" /* Relation */]: "link",
180
- ["species" /* Species */]: "crib",
181
- ["title" /* Title */]: "military_tech",
182
- ["trait" /* Trait */]: "flaky",
183
- ["zone" /* Zone */]: "architecture"
184
- };
185
- var FIELD_SCHEMA = {
186
- ability: {
187
- // Base fields (shared by all elements)
188
- name: { type: "text", required: true },
189
- description: { type: "text", required: false },
190
- supertype: { type: "text", required: false },
191
- subtype: { type: "text", required: false },
192
- image_url: { type: "text", required: false },
193
- // Mechanics
194
- activation: { type: "text" },
195
- duration: { type: "number" },
196
- potency: { type: "number" },
197
- range: { type: "number" },
198
- effects: { type: "multi_link", target: "phenomenon" },
199
- challenges: { type: "text" },
200
- talents: { type: "multi_link", target: "trait" },
201
- requisites: { type: "multi_link", target: "construct" },
202
- // World
203
- prevalence: { type: "text" },
204
- tradition: { type: "single_link", target: "construct" },
205
- source: { type: "single_link", target: "phenomenon" },
206
- locus: { type: "single_link", target: "location" },
207
- instruments: { type: "multi_link", target: "object" },
208
- systems: { type: "multi_link", target: "construct" }
209
- },
210
- character: {
211
- // Base fields (shared by all elements)
212
- name: { type: "text", required: true },
213
- description: { type: "text", required: false },
214
- supertype: { type: "text", required: false },
215
- subtype: { type: "text", required: false },
216
- image_url: { type: "text", required: false },
217
- // Constitution
218
- physicality: { type: "text" },
219
- mentality: { type: "text" },
220
- height: { type: "number" },
221
- weight: { type: "number" },
222
- species: { type: "multi_link", target: "species" },
223
- traits: { type: "multi_link", target: "trait" },
224
- abilities: { type: "multi_link", target: "ability" },
225
- // Origins
226
- background: { type: "text" },
227
- motivations: { type: "text" },
228
- birth_date: { type: "number" },
229
- birthplace: { type: "single_link", target: "location" },
230
- languages: { type: "multi_link", target: "language" },
231
- // World
232
- reputation: { type: "text" },
233
- location: { type: "single_link", target: "location" },
234
- objects: { type: "multi_link", target: "object" },
235
- institutions: { type: "multi_link", target: "institution" },
236
- // Personality
237
- charisma: { type: "number" },
238
- coercion: { type: "number" },
239
- competence: { type: "number" },
240
- compassion: { type: "number" },
241
- creativity: { type: "number" },
242
- courage: { type: "number" },
243
- // Social
244
- family: { type: "multi_link", target: "family" },
245
- friends: { type: "multi_link", target: "character" },
246
- rivals: { type: "multi_link", target: "character" },
247
- // TTRPG
248
- level: { type: "number" },
249
- hit_points: { type: "number" },
250
- STR: { type: "number" },
251
- DEX: { type: "number" },
252
- CON: { type: "number" },
253
- INT: { type: "number" },
254
- WIS: { type: "number" },
255
- CHA: { type: "number" }
256
- },
257
- collective: {
258
- // Base fields (shared by all elements)
259
- name: { type: "text", required: true },
260
- description: { type: "text", required: false },
261
- supertype: { type: "text", required: false },
262
- subtype: { type: "text", required: false },
263
- image_url: { type: "text", required: false },
264
- // Formation
265
- composition: { type: "text" },
266
- count: { type: "number" },
267
- formation_date: { type: "number" },
268
- operator: { type: "single_link", target: "institution" },
269
- equipment: { type: "multi_link", target: "construct" },
270
- // Dynamics
271
- activity: { type: "text" },
272
- disposition: { type: "text" },
273
- state: { type: "text" },
274
- abilities: { type: "multi_link", target: "ability" },
275
- symbolism: { type: "multi_link", target: "construct" },
276
- // World
277
- species: { type: "multi_link", target: "species" },
278
- characters: { type: "multi_link", target: "character" },
279
- creatures: { type: "multi_link", target: "creature" },
280
- phenomena: { type: "multi_link", target: "phenomenon" }
281
- },
282
- construct: {
283
- // Base fields (shared by all elements)
284
- name: { type: "text", required: true },
285
- description: { type: "text", required: false },
286
- supertype: { type: "text", required: false },
287
- subtype: { type: "text", required: false },
288
- image_url: { type: "text", required: false },
289
- // Nature
290
- rationale: { type: "text" },
291
- history: { type: "text" },
292
- status: { type: "text" },
293
- reach: { type: "text" },
294
- start_date: { type: "number" },
295
- end_date: { type: "number" },
296
- founder: { type: "single_link", target: "character" },
297
- custodian: { type: "single_link", target: "institution" },
298
- // Involves
299
- characters: { type: "multi_link", target: "character" },
300
- objects: { type: "multi_link", target: "object" },
301
- locations: { type: "multi_link", target: "location" },
302
- species: { type: "multi_link", target: "species" },
303
- creatures: { type: "multi_link", target: "creature" },
304
- institutions: { type: "multi_link", target: "institution" },
305
- traits: { type: "multi_link", target: "trait" },
306
- collectives: { type: "multi_link", target: "collective" },
307
- zones: { type: "multi_link", target: "zone" },
308
- abilities: { type: "multi_link", target: "ability" },
309
- phenomena: { type: "multi_link", target: "phenomenon" },
310
- languages: { type: "multi_link", target: "language" },
311
- families: { type: "multi_link", target: "family" },
312
- relations: { type: "multi_link", target: "relation" },
313
- titles: { type: "multi_link", target: "title" },
314
- constructs: { type: "multi_link", target: "construct" },
315
- events: { type: "multi_link", target: "event" },
316
- narratives: { type: "multi_link", target: "narrative" }
317
- },
318
- creature: {
319
- // Base fields (shared by all elements)
320
- name: { type: "text", required: true },
321
- description: { type: "text", required: false },
322
- supertype: { type: "text", required: false },
323
- subtype: { type: "text", required: false },
324
- image_url: { type: "text", required: false },
325
- // Biology
326
- appearance: { type: "text" },
327
- weight: { type: "number" },
328
- height: { type: "number" },
329
- species: { type: "multi_link", target: "species" },
330
- // Behaviour
331
- habits: { type: "text" },
332
- demeanor: { type: "text" },
333
- traits: { type: "multi_link", target: "trait" },
334
- abilities: { type: "multi_link", target: "ability" },
335
- languages: { type: "multi_link", target: "language" },
336
- // World
337
- status: { type: "text" },
338
- birth_date: { type: "number" },
339
- location: { type: "single_link", target: "location" },
340
- zone: { type: "single_link", target: "zone" },
341
- // TTRPG
342
- challenge_rating: { type: "number" },
343
- hit_points: { type: "number" },
344
- armor_class: { type: "number" },
345
- speed: { type: "number" },
346
- actions: { type: "multi_link", target: "ability" }
347
- },
348
- event: {
349
- // Base fields (shared by all elements)
350
- name: { type: "text", required: true },
351
- description: { type: "text", required: false },
352
- supertype: { type: "text", required: false },
353
- subtype: { type: "text", required: false },
354
- image_url: { type: "text", required: false },
355
- // Nature
356
- history: { type: "text" },
357
- challenges: { type: "text" },
358
- consequences: { type: "text" },
359
- start_date: { type: "number" },
360
- end_date: { type: "number" },
361
- triggers: { type: "multi_link", target: "event" },
362
- // Involves
363
- characters: { type: "multi_link", target: "character" },
364
- objects: { type: "multi_link", target: "object" },
365
- locations: { type: "multi_link", target: "location" },
366
- species: { type: "multi_link", target: "species" },
367
- creatures: { type: "multi_link", target: "creature" },
368
- institutions: { type: "multi_link", target: "institution" },
369
- traits: { type: "multi_link", target: "trait" },
370
- collectives: { type: "multi_link", target: "collective" },
371
- zones: { type: "multi_link", target: "zone" },
372
- abilities: { type: "multi_link", target: "ability" },
373
- phenomena: { type: "multi_link", target: "phenomenon" },
374
- languages: { type: "multi_link", target: "language" },
375
- families: { type: "multi_link", target: "family" },
376
- relations: { type: "multi_link", target: "relation" },
377
- titles: { type: "multi_link", target: "title" },
378
- constructs: { type: "multi_link", target: "construct" }
379
- },
380
- family: {
381
- // Base fields (shared by all elements)
382
- name: { type: "text", required: true },
383
- description: { type: "text", required: false },
384
- supertype: { type: "text", required: false },
385
- subtype: { type: "text", required: false },
386
- image_url: { type: "text", required: false },
387
- // Identity
388
- spirit: { type: "text" },
389
- history: { type: "text" },
390
- traditions: { type: "multi_link", target: "construct" },
391
- traits: { type: "multi_link", target: "trait" },
392
- abilities: { type: "multi_link", target: "ability" },
393
- languages: { type: "multi_link", target: "language" },
394
- ancestors: { type: "multi_link", target: "character" },
395
- // World
396
- reputation: { type: "text" },
397
- estates: { type: "multi_link", target: "location" },
398
- governs: { type: "multi_link", target: "institution" },
399
- heirlooms: { type: "multi_link", target: "object" },
400
- creatures: { type: "multi_link", target: "creature" }
401
- },
402
- institution: {
403
- // Base fields (shared by all elements)
404
- name: { type: "text", required: true },
405
- description: { type: "text", required: false },
406
- supertype: { type: "text", required: false },
407
- subtype: { type: "text", required: false },
408
- image_url: { type: "text", required: false },
409
- // Foundation
410
- doctrine: { type: "text" },
411
- founding_date: { type: "number" },
412
- parent_institution: { type: "single_link", target: "institution" },
413
- // Claims
414
- zones: { type: "multi_link", target: "zone" },
415
- objects: { type: "multi_link", target: "object" },
416
- creatures: { type: "multi_link", target: "creature" },
417
- // World
418
- status: { type: "text" },
419
- allies: { type: "multi_link", target: "institution" },
420
- adversaries: { type: "multi_link", target: "institution" },
421
- constructs: { type: "multi_link", target: "construct" }
422
- },
423
- language: {
424
- // Base fields (shared by all elements)
425
- name: { type: "text", required: true },
426
- description: { type: "text", required: false },
427
- supertype: { type: "text", required: false },
428
- subtype: { type: "text", required: false },
429
- image_url: { type: "text", required: false },
430
- // Structure
431
- phonology: { type: "text" },
432
- grammar: { type: "text" },
433
- lexicon: { type: "text" },
434
- writing: { type: "text" },
435
- classification: { type: "single_link", target: "construct" },
436
- // World
437
- status: { type: "text" },
438
- spread: { type: "multi_link", target: "location" },
439
- dialects: { type: "multi_link", target: "language" }
440
- },
441
- law: {
442
- // Base fields (shared by all elements)
443
- name: { type: "text", required: true },
444
- description: { type: "text", required: false },
445
- supertype: { type: "text", required: false },
446
- subtype: { type: "text", required: false },
447
- image_url: { type: "text", required: false },
448
- // Code
449
- declaration: { type: "text" },
450
- purpose: { type: "text" },
451
- date: { type: "number" },
452
- parent_law: { type: "single_link", target: "law" },
453
- penalties: { type: "multi_link", target: "construct" },
454
- // World
455
- author: { type: "single_link", target: "institution" },
456
- locations: { type: "multi_link", target: "location" },
457
- zones: { type: "multi_link", target: "zone" },
458
- prohibitions: { type: "multi_link", target: "construct" },
459
- adjudicators: { type: "multi_link", target: "title" },
460
- enforcers: { type: "multi_link", target: "title" }
461
- },
462
- location: {
463
- // Base fields (shared by all elements)
464
- name: { type: "text", required: true },
465
- description: { type: "text", required: false },
466
- supertype: { type: "text", required: false },
467
- subtype: { type: "text", required: false },
468
- image_url: { type: "text", required: false },
469
- // Setting
470
- form: { type: "text" },
471
- function: { type: "text" },
472
- founding_date: { type: "number" },
473
- parent_location: { type: "single_link", target: "location" },
474
- populations: { type: "multi_link", target: "collective" },
475
- // Politics
476
- political_climate: { type: "text" },
477
- primary_power: { type: "single_link", target: "institution" },
478
- governing_title: { type: "single_link", target: "title" },
479
- secondary_powers: { type: "multi_link", target: "institution" },
480
- zone: { type: "single_link", target: "zone" },
481
- rival: { type: "single_link", target: "location" },
482
- partner: { type: "single_link", target: "location" },
483
- // World
484
- customs: { type: "text" },
485
- founders: { type: "multi_link", target: "character" },
486
- cults: { type: "multi_link", target: "construct" },
487
- delicacies: { type: "multi_link", target: "species" },
488
- // Production
489
- extraction_methods: { type: "multi_link", target: "construct" },
490
- extraction_goods: { type: "multi_link", target: "construct" },
491
- industry_methods: { type: "multi_link", target: "construct" },
492
- industry_goods: { type: "multi_link", target: "construct" },
493
- // Commerce
494
- infrastructure: { type: "text" },
495
- extraction_markets: { type: "multi_link", target: "location" },
496
- industry_markets: { type: "multi_link", target: "location" },
497
- currencies: { type: "multi_link", target: "construct" },
498
- // Construction
499
- architecture: { type: "text" },
500
- buildings: { type: "multi_link", target: "object" },
501
- building_methods: { type: "multi_link", target: "construct" },
502
- // Defense
503
- defensibility: { type: "text" },
504
- elevation: { type: "number" },
505
- fighters: { type: "multi_link", target: "construct" },
506
- defensive_objects: { type: "multi_link", target: "object" }
507
- },
508
- map: {
509
- // Base fields (shared by all elements)
510
- name: { type: "text", required: true },
511
- description: { type: "text", required: false },
512
- supertype: { type: "text", required: false },
513
- subtype: { type: "text", required: false },
514
- image_url: { type: "text", required: false },
515
- // Details
516
- background_color: { type: "text" },
517
- hierarchy: { type: "number" },
518
- width: { type: "number" },
519
- height: { type: "number" },
520
- depth: { type: "number" },
521
- parent_map: { type: "single_link", target: "map" },
522
- location: { type: "single_link", target: "location" }
523
- },
524
- marker: {
525
- // Base fields (shared by all elements)
526
- name: { type: "text", required: true },
527
- description: { type: "text", required: false },
528
- supertype: { type: "text", required: false },
529
- subtype: { type: "text", required: false },
530
- image_url: { type: "text", required: false },
531
- // Details
532
- map: { type: "single_link", target: "map", required: true },
533
- zone: { type: "single_link", target: "zone", required: true },
534
- x: { type: "number", required: true },
535
- y: { type: "number", required: true },
536
- z: { type: "number" },
537
- order: { type: "number", required: true }
538
- },
539
- narrative: {
540
- // Base fields (shared by all elements)
541
- name: { type: "text", required: true },
542
- description: { type: "text", required: false },
543
- supertype: { type: "text", required: false },
544
- subtype: { type: "text", required: false },
545
- image_url: { type: "text", required: false },
546
- // Context
547
- story: { type: "text" },
548
- consequences: { type: "text" },
549
- start_date: { type: "number" },
550
- end_date: { type: "number" },
551
- order: { type: "number" },
552
- parent_narrative: { type: "single_link", target: "narrative" },
553
- protagonist: { type: "single_link", target: "character" },
554
- antagonist: { type: "single_link", target: "character" },
555
- narrator: { type: "single_link", target: "character" },
556
- conservator: { type: "single_link", target: "institution" },
557
- // Involves
558
- events: { type: "multi_link", target: "event" },
559
- characters: { type: "multi_link", target: "character" },
560
- objects: { type: "multi_link", target: "object" },
561
- locations: { type: "multi_link", target: "location" },
562
- species: { type: "multi_link", target: "species" },
563
- creatures: { type: "multi_link", target: "creature" },
564
- institutions: { type: "multi_link", target: "institution" },
565
- traits: { type: "multi_link", target: "trait" },
566
- collectives: { type: "multi_link", target: "collective" },
567
- zones: { type: "multi_link", target: "zone" },
568
- abilities: { type: "multi_link", target: "ability" },
569
- phenomena: { type: "multi_link", target: "phenomenon" },
570
- languages: { type: "multi_link", target: "language" },
571
- families: { type: "multi_link", target: "family" },
572
- relations: { type: "multi_link", target: "relation" },
573
- titles: { type: "multi_link", target: "title" },
574
- constructs: { type: "multi_link", target: "construct" },
575
- laws: { type: "multi_link", target: "law" }
576
- },
577
- object: {
578
- // Base fields (shared by all elements)
579
- name: { type: "text", required: true },
580
- description: { type: "text", required: false },
581
- supertype: { type: "text", required: false },
582
- subtype: { type: "text", required: false },
583
- image_url: { type: "text", required: false },
584
- // Form
585
- aesthetics: { type: "text" },
586
- weight: { type: "number" },
587
- amount: { type: "number" },
588
- parent_object: { type: "single_link", target: "object" },
589
- materials: { type: "multi_link", target: "construct" },
590
- technology: { type: "multi_link", target: "construct" },
591
- // Function
592
- utility: { type: "text" },
593
- effects: { type: "multi_link", target: "phenomenon" },
594
- abilities: { type: "multi_link", target: "ability" },
595
- consumes: { type: "multi_link", target: "construct" },
596
- // World
597
- origins: { type: "text" },
598
- location: { type: "single_link", target: "location" },
599
- language: { type: "single_link", target: "language" },
600
- affinities: { type: "multi_link", target: "trait" }
601
- },
602
- phenomenon: {
603
- // Base fields (shared by all elements)
604
- name: { type: "text", required: true },
605
- description: { type: "text", required: false },
606
- supertype: { type: "text", required: false },
607
- subtype: { type: "text", required: false },
608
- image_url: { type: "text", required: false },
609
- // Mechanics
610
- expression: { type: "text" },
611
- effects: { type: "text" },
612
- duration: { type: "number" },
613
- catalysts: { type: "multi_link", target: "object" },
614
- empowerments: { type: "multi_link", target: "ability" },
615
- // World
616
- mythology: { type: "text" },
617
- system: { type: "single_link", target: "phenomenon" },
618
- triggers: { type: "multi_link", target: "construct" },
619
- wielders: { type: "multi_link", target: "character" },
620
- environments: { type: "multi_link", target: "location" }
621
- },
622
- pin: {
623
- // Base fields (shared by all elements)
624
- name: { type: "text", required: true },
625
- description: { type: "text", required: false },
626
- supertype: { type: "text", required: false },
627
- subtype: { type: "text", required: false },
628
- image_url: { type: "text", required: false },
629
- // Details
630
- map: { type: "single_link", target: "map", required: true },
631
- element_type: { type: "text", required: true },
632
- // ElementType enum value; YAML 'element' generic-link is split into _type + _id
633
- element_id: { type: "single_link", target: "any", required: true },
634
- // Can reference any element
635
- x: { type: "number", required: true },
636
- y: { type: "number", required: true },
637
- z: { type: "number" }
638
- },
639
- relation: {
640
- // Base fields (shared by all elements)
641
- name: { type: "text", required: true },
642
- description: { type: "text", required: false },
643
- supertype: { type: "text", required: false },
644
- subtype: { type: "text", required: false },
645
- image_url: { type: "text", required: false },
646
- // Nature
647
- background: { type: "text" },
648
- start_date: { type: "number" },
649
- end_date: { type: "number" },
650
- intensity: { type: "number" },
651
- actor: { type: "single_link", target: "character" },
652
- events: { type: "multi_link", target: "event" },
653
- // Involves
654
- characters: { type: "multi_link", target: "character" },
655
- objects: { type: "multi_link", target: "object" },
656
- locations: { type: "multi_link", target: "location" },
657
- species: { type: "multi_link", target: "species" },
658
- creatures: { type: "multi_link", target: "creature" },
659
- institutions: { type: "multi_link", target: "institution" },
660
- traits: { type: "multi_link", target: "trait" },
661
- collectives: { type: "multi_link", target: "collective" },
662
- zones: { type: "multi_link", target: "zone" },
663
- abilities: { type: "multi_link", target: "ability" },
664
- phenomena: { type: "multi_link", target: "phenomenon" },
665
- languages: { type: "multi_link", target: "language" },
666
- families: { type: "multi_link", target: "family" },
667
- relations: { type: "multi_link", target: "relation" },
668
- titles: { type: "multi_link", target: "title" },
669
- constructs: { type: "multi_link", target: "construct" },
670
- narratives: { type: "multi_link", target: "narrative" }
671
- },
672
- species: {
673
- // Base fields (shared by all elements)
674
- name: { type: "text", required: true },
675
- description: { type: "text", required: false },
676
- supertype: { type: "text", required: false },
677
- subtype: { type: "text", required: false },
678
- image_url: { type: "text", required: false },
679
- // Biology
680
- appearance: { type: "text" },
681
- life_span: { type: "number" },
682
- weight: { type: "number" },
683
- nourishment: { type: "multi_link", target: "species" },
684
- reproduction: { type: "multi_link", target: "construct" },
685
- adaptations: { type: "multi_link", target: "ability" },
686
- // Psychology
687
- instincts: { type: "text" },
688
- sociality: { type: "text" },
689
- temperament: { type: "text" },
690
- communication: { type: "text" },
691
- aggression: { type: "number" },
692
- traits: { type: "multi_link", target: "trait" },
693
- // World
694
- role: { type: "text" },
695
- parent_species: { type: "single_link", target: "species" },
696
- locations: { type: "multi_link", target: "location" },
697
- zones: { type: "multi_link", target: "zone" },
698
- affinities: { type: "multi_link", target: "phenomenon" }
699
- },
700
- title: {
701
- // Base fields (shared by all elements)
702
- name: { type: "text", required: true },
703
- description: { type: "text", required: false },
704
- supertype: { type: "text", required: false },
705
- subtype: { type: "text", required: false },
706
- image_url: { type: "text", required: false },
707
- // Mandate
708
- authority: { type: "text" },
709
- eligibility: { type: "text" },
710
- grant_date: { type: "number" },
711
- revoke_date: { type: "number" },
712
- issuer: { type: "single_link", target: "institution" },
713
- body: { type: "single_link", target: "institution" },
714
- superior_title: { type: "single_link", target: "title" },
715
- holders: { type: "multi_link", target: "character" },
716
- symbols: { type: "multi_link", target: "object" },
717
- // World
718
- status: { type: "text" },
719
- history: { type: "text" },
720
- characters: { type: "multi_link", target: "character" },
721
- institutions: { type: "multi_link", target: "institution" },
722
- families: { type: "multi_link", target: "family" },
723
- zones: { type: "multi_link", target: "zone" },
724
- locations: { type: "multi_link", target: "location" },
725
- objects: { type: "multi_link", target: "object" },
726
- constructs: { type: "multi_link", target: "construct" },
727
- laws: { type: "multi_link", target: "law" },
728
- collectives: { type: "multi_link", target: "collective" },
729
- creatures: { type: "multi_link", target: "creature" },
730
- phenomena: { type: "multi_link", target: "phenomenon" },
731
- species: { type: "multi_link", target: "species" },
732
- languages: { type: "multi_link", target: "language" }
733
- },
734
- trait: {
735
- // Base fields (shared by all elements)
736
- name: { type: "text", required: true },
737
- description: { type: "text", required: false },
738
- supertype: { type: "text", required: false },
739
- subtype: { type: "text", required: false },
740
- image_url: { type: "text", required: false },
741
- // Qualitative
742
- social_effects: { type: "text" },
743
- physical_effects: { type: "text" },
744
- functional_effects: { type: "text" },
745
- personality_effects: { type: "text" },
746
- behaviour_effects: { type: "text" },
747
- // Quantitative
748
- charisma: { type: "number" },
749
- coercion: { type: "number" },
750
- competence: { type: "number" },
751
- compassion: { type: "number" },
752
- creativity: { type: "number" },
753
- courage: { type: "number" },
754
- // World
755
- significance: { type: "text" },
756
- anti_trait: { type: "single_link", target: "trait" },
757
- empowered_abilities: { type: "multi_link", target: "ability" }
758
- },
759
- zone: {
760
- // Base fields (shared by all elements)
761
- name: { type: "text", required: true },
762
- description: { type: "text", required: false },
763
- supertype: { type: "text", required: false },
764
- subtype: { type: "text", required: false },
765
- image_url: { type: "text", required: false },
766
- // Scope
767
- role: { type: "text" },
768
- start_date: { type: "number" },
769
- end_date: { type: "number" },
770
- phenomena: { type: "multi_link", target: "phenomenon" },
771
- linked_zones: { type: "multi_link", target: "zone" },
772
- // World
773
- context: { type: "text" },
774
- populations: { type: "multi_link", target: "collective" },
775
- titles: { type: "multi_link", target: "title" },
776
- principles: { type: "multi_link", target: "construct" }
777
- }
778
- };
779
- function createElementId(id) {
780
- return id;
781
- }
782
- function createElementIds(ids) {
783
- return ids;
784
- }
785
- function createAnyElementId(id) {
786
- return id;
787
- }
788
-
789
- // src/token-resource.ts
790
- var TokenResource = class {
791
- constructor(client) {
792
- this.client = client;
793
- }
794
- /**
795
- * Get current token status for authenticated user
796
- *
797
- * Returns daily token allowance, usage, and availability.
798
- * Matches base-tool's checkStatus() pattern.
799
- *
800
- * @returns Current token status
801
- * @example
802
- * ```typescript
803
- * const status = await client.tokens.getStatus();
804
- * console.log(`Available: ${status.tokens_available_today}/${status.token_rating}`);
805
- * console.log(`Used today: ${status.tokens_used_today}`);
806
- * console.log(`Active sessions: ${status.sessions_active}`);
807
- * ```
808
- */
809
- async getStatus() {
810
- return this.client.request("GET", "/tokens/status/");
811
- }
812
- /**
813
- * Consume tokens for service usage
814
- *
815
- * Reports token consumption to track daily usage. Allows consumption even if
816
- * exceeds available tokens (tracks as debt), but warns via error field.
817
- * Matches base-tool's reportUsage() pattern.
818
- *
819
- * @param params - Token consumption parameters
820
- * @returns Consumption result with updated balance
821
- * @example
822
- * ```typescript
823
- * const result = await client.tokens.consume({
824
- * amount: 500,
825
- * service: 'worldbuilding_tool',
826
- * metadata: {
827
- * feature: 'character_generation',
828
- * model: 'gpt-4',
829
- * prompt_tokens: 300,
830
- * completion_tokens: 200
831
- * }
832
- * });
833
- *
834
- * if (result.error) {
835
- * console.warn('Token warning:', result.error);
836
- * }
837
- * console.log(`${result.tokens_remaining} tokens remaining`);
838
- * ```
839
- */
840
- async consume(params) {
841
- return this.client.request("POST", "/tokens/consume/", {
842
- body: {
843
- amount: params.amount,
844
- service: params.service || "sdk_client",
845
- session_id: params.sessionId ?? null,
846
- metadata: params.metadata ?? null
847
- }
848
- });
849
- }
850
- /**
851
- * Get encrypted OpenAI API key (advanced use case)
852
- *
853
- * Requires minimum 100 tokens available. Creates a 1-hour session for tracking.
854
- * Returns encrypted key that must be decrypted client-side using Fernet.
855
- *
856
- * See base-tool/src/llm/token-service.ts:99-155 for full implementation example
857
- * including client-side decryption with the 'fernet' npm package.
858
- *
859
- * @returns Encrypted access key and session info
860
- * @throws Error if insufficient tokens (< 100)
861
- * @example
862
- * ```typescript
863
- * // Get encrypted key
864
- * const access = await client.tokens.getAccessKey();
865
- *
866
- * // Decrypt using fernet library (see base-tool for full example)
867
- * // 1. Derive key from world ID using SHA-256
868
- * // 2. Use 'fernet' npm package to decrypt
869
- * // 3. Use decrypted OpenAI key for direct API calls
870
- * // 4. Report usage with access.session_id
871
- *
872
- * console.log('Session:', access.session_id);
873
- * console.log('Expires:', access.expires_at);
874
- * ```
875
- */
876
- async getAccessKey() {
877
- return this.client.request("GET", "/tokens/access-key/");
878
- }
879
- /**
880
- * Revoke a specific token session
881
- *
882
- * Invalidates the session ID obtained from getAccessKey().
883
- * Use when cleaning up or on logout.
884
- *
885
- * @param sessionId - Session ID to revoke
886
- * @returns Revocation result
887
- * @example
888
- * ```typescript
889
- * await client.tokens.revokeSession('session-id-here');
890
- * ```
891
- */
892
- async revokeSession(sessionId) {
893
- return this.client.request(
894
- "POST",
895
- `/tokens/revoke-session/?session_id=${encodeURIComponent(sessionId)}`
896
- );
897
- }
898
- /**
899
- * Revoke all active sessions (emergency use)
900
- *
901
- * Invalidates all token sessions for the authenticated user.
902
- * Use for security cleanup or when sessions are stuck.
903
- *
904
- * @returns Revocation result with count of revoked sessions
905
- * @example
906
- * ```typescript
907
- * const result = await client.tokens.revokeAllSessions();
908
- * console.log(`Revoked ${result.sessions_revoked} sessions`);
909
- * ```
910
- */
911
- async revokeAllSessions() {
912
- return this.client.request("POST", "/tokens/revoke-all-sessions/");
913
- }
914
- /**
915
- * Get public encryption info (no auth required)
916
- *
917
- * Returns algorithm details and example code for client-side decryption.
918
- * Public endpoint - can be called without authentication.
919
- *
920
- * @returns Encryption algorithm and implementation details
921
- * @example
922
- * ```typescript
923
- * const info = await client.tokens.getEncryptionInfo();
924
- * console.log('Algorithm:', info.algorithm);
925
- * console.log('Key derivation:', info.key_derivation);
926
- * console.log(info.javascript_example);
927
- * ```
928
- */
929
- async getEncryptionInfo() {
930
- return this.client.request("GET", "/tokens/encryption-info/");
931
- }
932
- };
933
-
934
- // src/client.ts
935
- var Resource = class {
936
- constructor(client, elementType) {
937
- this.client = client;
938
- this.elementType = elementType;
939
- }
940
- async list(options) {
941
- const response = await this.client.request("GET", `/${this.elementType}/`, { params: options });
942
- if (Array.isArray(response)) {
943
- return {
944
- count: response.length,
945
- next: null,
946
- previous: null,
947
- results: response
948
- };
949
- }
950
- return response;
951
- }
952
- async get(id) {
953
- return this.client.request("GET", `/${this.elementType}/${id}/`);
954
- }
955
- async create(data) {
956
- let body = OnlyWorldsClient.prepareRelations(data, this.elementType);
957
- if (this.elementType === "pin") body = this.roundPinCoordinates(body);
958
- return this.client.request("POST", `/${this.elementType}/`, { body });
959
- }
960
- async update(id, data) {
961
- let body = OnlyWorldsClient.prepareRelations(data, this.elementType);
962
- if (this.elementType === "pin") body = this.roundPinCoordinates(body);
963
- return this.client.request("PATCH", `/${this.elementType}/${id}/`, { body });
964
- }
965
- async delete(id) {
966
- return this.client.request("DELETE", `/${this.elementType}/${id}/`);
967
- }
968
- /**
969
- * Round Pin coordinates to integers (API requirement)
970
- * @private
971
- */
972
- roundPinCoordinates(data) {
973
- const rounded = { ...data };
974
- if (typeof rounded.x === "number") rounded.x = Math.round(rounded.x);
975
- if (typeof rounded.y === "number") rounded.y = Math.round(rounded.y);
976
- if (typeof rounded.z === "number") rounded.z = Math.round(rounded.z);
977
- return rounded;
978
- }
979
- };
980
- var WorldResource = class {
981
- constructor(client) {
982
- this.client = client;
983
- }
984
- /**
985
- * Get the world associated with the current API key
986
- * Returns the world directly (not wrapped in pagination)
987
- */
988
- async get() {
989
- return this.client.request("GET", "/world/");
990
- }
991
- /**
992
- * Update the current world
993
- */
994
- async update(data) {
995
- return this.client.request("PATCH", "/world/", { body: data });
996
- }
997
- };
998
- var OnlyWorldsClient = class {
999
- constructor(config) {
1000
- this.baseUrl = config.baseUrl || "https://www.onlyworlds.com/api/worldapi";
1001
- this.headers = {
1002
- "Content-Type": "application/json",
1003
- "API-Key": config.apiKey,
1004
- "API-Pin": config.apiPin
1005
- };
1006
- this.worlds = new WorldResource(this);
1007
- this.tokens = new TokenResource(this);
1008
- this.abilities = new Resource(this, "ability");
1009
- this.characters = new Resource(this, "character");
1010
- this.collectives = new Resource(this, "collective");
1011
- this.constructs = new Resource(this, "construct");
1012
- this.creatures = new Resource(this, "creature");
1013
- this.events = new Resource(this, "event");
1014
- this.families = new Resource(this, "family");
1015
- this.institutions = new Resource(this, "institution");
1016
- this.languages = new Resource(this, "language");
1017
- this.laws = new Resource(this, "law");
1018
- this.locations = new Resource(this, "location");
1019
- this.maps = new Resource(this, "map");
1020
- this.markers = new Resource(this, "marker");
1021
- this.narratives = new Resource(this, "narrative");
1022
- this.objects = new Resource(this, "object");
1023
- this.phenomena = new Resource(this, "phenomenon");
1024
- this.pins = new Resource(this, "pin");
1025
- this.relations = new Resource(this, "relation");
1026
- this.species = new Resource(this, "species");
1027
- this.titles = new Resource(this, "title");
1028
- this.traits = new Resource(this, "trait");
1029
- this.zones = new Resource(this, "zone");
1030
- }
1031
- /**
1032
- * Make a request to the OnlyWorlds API
1033
- */
1034
- async request(method, path, options) {
1035
- const url = new URL(`${this.baseUrl}${path}`);
1036
- if (options?.params) {
1037
- Object.entries(options.params).forEach(([key, value]) => {
1038
- if (value !== void 0 && value !== null) {
1039
- url.searchParams.append(key, String(value));
1040
- }
1041
- });
1042
- }
1043
- const fetchOptions = {
1044
- method,
1045
- headers: this.headers
1046
- };
1047
- if (options?.body && ["POST", "PATCH", "PUT"].includes(method)) {
1048
- fetchOptions.body = JSON.stringify(options.body);
1049
- }
1050
- const response = await fetch(url.toString(), fetchOptions);
1051
- if (!response.ok) {
1052
- let errorMessage = `API Error ${response.status}`;
1053
- try {
1054
- const errorText = await response.text();
1055
- if (errorText) {
1056
- try {
1057
- const errorJson = JSON.parse(errorText);
1058
- if (Array.isArray(errorJson.detail)) {
1059
- const validationErrors = errorJson.detail.map((err) => {
1060
- const location = err.loc ? err.loc.join(".") : "unknown";
1061
- return `${location}: ${err.msg}`;
1062
- }).join("; ");
1063
- errorMessage += `: ${validationErrors}`;
1064
- } else {
1065
- errorMessage += `: ${errorJson.detail || errorJson.error || errorText}`;
1066
- }
1067
- } catch {
1068
- errorMessage += `: ${errorText}`;
1069
- }
1070
- }
1071
- } catch {
1072
- }
1073
- throw new Error(errorMessage);
1074
- }
1075
- if (response.status === 204) {
1076
- return void 0;
1077
- }
1078
- return response.json();
1079
- }
1080
- /**
1081
- * Helper to convert nested objects to _id/_ids format (legacy method)
1082
- * @deprecated Use prepareRelations instead - it's called automatically in create/update
1083
- */
1084
- static prepareInput(data) {
1085
- const result = { ...data };
1086
- for (const [key, value] of Object.entries(result)) {
1087
- if (value && typeof value === "object" && !Array.isArray(value) && "id" in value) {
1088
- delete result[key];
1089
- result[`${key}_id`] = value.id;
1090
- } else if (Array.isArray(value) && value.length > 0 && typeof value[0] === "object" && "id" in value[0]) {
1091
- delete result[key];
1092
- result[`${key}_ids`] = value.map((item) => item.id);
1093
- }
1094
- }
1095
- return result;
1096
- }
1097
- /**
1098
- * Convert relation fields to API format (_id/_ids suffix)
1099
- *
1100
- * The OnlyWorlds API expects:
1101
- * - single_link fields: fieldname_id (e.g., birthplace_id)
1102
- * - multi_link fields: fieldname_ids (e.g., species_ids)
1103
- *
1104
- * This method auto-converts based on FIELD_SCHEMA:
1105
- * - { species: ["id1", "id2"] } → { species_ids: ["id1", "id2"] }
1106
- * - { birthplace: "location-id" } → { birthplace_id: "location-id" }
1107
- * - { species: [{id: "id1", name: "X"}] } → { species_ids: ["id1"] }
1108
- *
1109
- * Called automatically by create() and update() methods.
1110
- */
1111
- static prepareRelations(data, elementType) {
1112
- const schema = FIELD_SCHEMA[elementType];
1113
- if (!schema) return data;
1114
- const result = { ...data };
1115
- for (const [key, value] of Object.entries(result)) {
1116
- const fieldDef = schema[key];
1117
- if (!fieldDef) continue;
1118
- if (fieldDef.type === "single_link") {
1119
- delete result[key];
1120
- if (value && typeof value === "object" && "id" in value) {
1121
- result[`${key}_id`] = value.id;
1122
- } else if (typeof value === "string" || value === null) {
1123
- result[`${key}_id`] = value;
1124
- }
1125
- } else if (fieldDef.type === "multi_link") {
1126
- delete result[key];
1127
- if (Array.isArray(value)) {
1128
- if (value.length > 0 && typeof value[0] === "object" && "id" in value[0]) {
1129
- result[`${key}_ids`] = value.map((item) => item.id);
1130
- } else {
1131
- result[`${key}_ids`] = value;
1132
- }
1133
- } else {
1134
- result[`${key}_ids`] = [];
1135
- }
1136
- }
1137
- }
1138
- return result;
1139
- }
1140
- };
1141
-
1142
- // src/token-types.ts
1143
- var GameTier = /* @__PURE__ */ ((GameTier2) => {
1144
- GameTier2["FREE"] = "free";
1145
- GameTier2["SILVER"] = "silver";
1146
- GameTier2["GOLD"] = "gold";
1147
- GameTier2["PLATINUM"] = "platinum";
1148
- GameTier2["DIAMOND"] = "diamond";
1149
- GameTier2["DELUXE"] = "deluxe";
1150
- return GameTier2;
1151
- })(GameTier || {});
1152
-
1153
- // src/icon-utils.ts
1154
- var PLURAL_TO_SINGULAR = {
1155
- abilities: "ability" /* Ability */,
1156
- characters: "character" /* Character */,
1157
- collectives: "collective" /* Collective */,
1158
- constructs: "construct" /* Construct */,
1159
- creatures: "creature" /* Creature */,
1160
- events: "event" /* Event */,
1161
- families: "family" /* Family */,
1162
- institutions: "institution" /* Institution */,
1163
- languages: "language" /* Language */,
1164
- laws: "law" /* Law */,
1165
- locations: "location" /* Location */,
1166
- maps: "map" /* Map */,
1167
- markers: "marker" /* Marker */,
1168
- narratives: "narrative" /* Narrative */,
1169
- objects: "object" /* Object */,
1170
- phenomena: "phenomenon" /* Phenomenon */,
1171
- // irregular plural
1172
- pins: "pin" /* Pin */,
1173
- relations: "relation" /* Relation */,
1174
- species: "species" /* Species */,
1175
- // same singular/plural
1176
- titles: "title" /* Title */,
1177
- traits: "trait" /* Trait */,
1178
- zones: "zone" /* Zone */
1179
- };
1180
- function getElementIcon(type) {
1181
- const lower = type.toLowerCase();
1182
- if (lower in PLURAL_TO_SINGULAR) {
1183
- return ELEMENT_ICONS[PLURAL_TO_SINGULAR[lower]];
1184
- }
1185
- const singular = Object.values(ElementType).find(
1186
- (et) => et.toLowerCase() === lower
1187
- );
1188
- if (singular) {
1189
- return ELEMENT_ICONS[singular];
1190
- }
1191
- return "help_outline";
1192
- }
1193
-
1194
- // src/v2/errors.ts
1195
- var OwApiError = class extends Error {
1196
- constructor(status, code, message, docUrl, detail, type = null, param = null) {
1197
- super(message);
1198
- this.name = "OwApiError";
1199
- this.status = status;
1200
- this.code = code;
1201
- this.type = type;
1202
- this.param = param;
1203
- this.docUrl = docUrl;
1204
- this.detail = detail;
1205
- }
1206
- get isAuthError() {
1207
- return this.code === "invalid_credentials" || this.code === "key_revoked" || this.code === "world_gone";
1208
- }
1209
- /** 422s/400s name the offending param/field -- typos error loudly platform-wide. */
1210
- get isValidationError() {
1211
- return this.status === 422 || this.status === 400;
1212
- }
1213
- /** Same Idempotency-Key replayed with a different payload. */
1214
- get isIdempotencyConflict() {
1215
- return this.status === 409;
1216
- }
1217
- };
1218
- var OwNetworkError = class extends Error {
1219
- constructor(message, cause) {
1220
- super(message);
1221
- this.name = "OwNetworkError";
1222
- this.cause2 = cause;
1223
- }
1224
- };
1225
- function parseEnvelope(status, body) {
1226
- const env = body && typeof body === "object" ? body : {};
1227
- const nested = typeof env.error === "object" && env.error !== null ? env.error : void 0;
1228
- const code = env.code ?? nested?.code ?? (typeof env.error === "string" ? env.error : null) ?? null;
1229
- const type = env.type ?? nested?.type ?? null;
1230
- const param = env.param ?? nested?.param ?? null;
1231
- const docUrl = env.doc_url ?? nested?.doc_url ?? null;
1232
- const message = env.message ?? nested?.message ?? (typeof env.detail === "string" ? env.detail : void 0) ?? `OnlyWorlds API error ${status}${code ? ` (${code})` : ""}`;
1233
- return new OwApiError(status, code, message, docUrl, body, type, param);
1234
- }
1235
- async function errorFromResponse(res) {
1236
- let body = null;
1237
- let text = "";
1238
- try {
1239
- text = await res.text();
1240
- body = text ? JSON.parse(text) : null;
1241
- } catch {
1242
- body = text || null;
1243
- }
1244
- return parseEnvelope(res.status, body);
1245
- }
1246
-
1247
- // src/v2/keys.ts
1248
- var LEGACY_RE = /^[0-9]{10}$/;
1249
- function isDemoKey(key) {
1250
- return LEGACY_RE.test(key) && key >= "0000000000" && key <= "0000000009";
1251
- }
1252
- function detectKeyKind(key) {
1253
- if (key.startsWith("ow_w_")) return "write";
1254
- if (key.startsWith("ow_r_")) return "read";
1255
- if (key.startsWith("ow_a_")) return "account";
1256
- if (LEGACY_RE.test(key)) return "legacy";
1257
- return "unknown";
1258
- }
1259
- function kindCanWrite(kind) {
1260
- return kind === "write" || kind === "legacy";
1261
- }
1262
- function pinExpectation(kind) {
1263
- switch (kind) {
1264
- case "read":
1265
- return "never";
1266
- case "account":
1267
- return "never";
1268
- case "write":
1269
- return "optional";
1270
- case "legacy":
1271
- return "required-for-private-reads";
1272
- default:
1273
- return "optional";
1274
- }
1275
- }
1276
-
1277
- // src/v2/client.ts
1278
- var DEFAULT_BASE_URL = "https://www.onlyworlds.com/api/v2";
1279
- var DEFAULT_PAGE_SIZE = 100;
1280
- var DEFAULT_CHANGES_PAGE_SIZE = 100;
1281
- var OwV2Client = class {
1282
- constructor(config) {
1283
- if (!config.apiKey) throw new Error("OwV2Client: apiKey is required");
1284
- this.apiKey = config.apiKey;
1285
- this.apiPin = config.apiPin || void 0;
1286
- this.keyKind = detectKeyKind(config.apiKey);
1287
- this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
1288
- this.pageSize = config.pageSize ?? DEFAULT_PAGE_SIZE;
1289
- this.changesPageSize = config.changesPageSize ?? DEFAULT_CHANGES_PAGE_SIZE;
1290
- this.fetchImpl = config.fetch ?? globalThis.fetch.bind(globalThis);
1291
- if (typeof this.fetchImpl !== "function") {
1292
- throw new Error("OwV2Client: no fetch available -- supply config.fetch");
1293
- }
1294
- }
1295
- // -- Health & world meta -------------------------------------------------
1296
- /** GET /health -- unauthenticated liveness pulse. */
1297
- async health() {
1298
- return this.request("GET", "/health/", { auth: false });
1299
- }
1300
- /**
1301
- * GET /world -- world meta (name, calendar/time fields, public_read).
1302
- * GOTCHA (by server design): world-meta edits do NOT appear in /changes and
1303
- * do not bump change_seq. Poll getWorld().updated_at for meta freshness.
1304
- */
1305
- async getWorld() {
1306
- return this.request("GET", "/world/");
1307
- }
1308
- /** PATCH /world -- partial world-meta update. */
1309
- async patchWorld(partial) {
1310
- return this.request("PATCH", "/world/", { body: sanitizePayload(partial) });
1311
- }
1312
- // -- Element CRUD --------------------------------------------------------
1313
- /** GET /{type}/ -- one cursor page. */
1314
- async list(type, params = {}) {
1315
- const query = buildQuery({
1316
- limit: params.limit ?? this.pageSize,
1317
- cursor: params.cursor,
1318
- expand: params.expand?.join(","),
1319
- fields: params.fields?.join(","),
1320
- ...params.filter
1321
- });
1322
- return this.request("GET", `/${type}/`, { query });
1323
- }
1324
- /** Cursor-walk every page of a type. Politeness: uses config pageSize. */
1325
- async *listAll(type, params = {}) {
1326
- let cursor;
1327
- do {
1328
- const page = await this.list(type, { ...params, cursor });
1329
- for (const el of page.data) yield el;
1330
- cursor = page.has_more && page.next_cursor ? page.next_cursor : void 0;
1331
- } while (cursor);
1332
- }
1333
- /** GET /{type}/{id}/ -- optional one-level stub expansion / sparse fields. */
1334
- async get(type, id, opts = {}) {
1335
- const query = buildQuery({ expand: opts.expand?.join(","), fields: opts.fields?.join(",") });
1336
- return this.request("GET", `/${type}/${id}/`, { query });
1337
- }
1338
- /**
1339
- * POST /{type}/ -- create. Mints an RFC-4122 UUID for element.id when the
1340
- * caller omits one (design ruling D29d) so a retry carrying the same
1341
- * Idempotency-Key is structurally safe. Callers MAY still supply their own id.
1342
- */
1343
- async create(type, element, opts = {}) {
1344
- const body = sanitizePayload(element);
1345
- if (body.id === void 0 || body.id === null || body.id === "") {
1346
- body.id = mintUuid();
1347
- }
1348
- return this.request("POST", `/${type}/`, {
1349
- body,
1350
- idempotencyKey: opts.idempotencyKey
1351
- });
1352
- }
1353
- /** PUT /{type}/{id}/ -- upsert-by-client-id. The local-first write primitive. */
1354
- async upsert(type, id, element) {
1355
- return this.request("PUT", `/${type}/${id}/`, { body: sanitizePayload(element) });
1356
- }
1357
- /**
1358
- * PATCH /{type}/{id}/ -- partial update. DESTRUCTIVE on sent fields: arrays
1359
- * replace wholesale, omitted fields stay untouched. For link arrays prefer
1360
- * editLinks() -- atomic server-side merge, no read-before-write.
1361
- */
1362
- async patch(type, id, partial) {
1363
- return this.request("PATCH", `/${type}/${id}/`, { body: sanitizePayload(partial) });
1364
- }
1365
- /**
1366
- * DELETE /{type}/{id}/ -- idempotent (204 on absent). Server writes a
1367
- * tombstone AND scrubs the id from every other element's links in the same
1368
- * transaction -- no client-side unlink pass needed, ever.
1369
- */
1370
- async delete(type, id) {
1371
- await this.request("DELETE", `/${type}/${id}/`, { allowEmpty: true });
1372
- }
1373
- /**
1374
- * POST /{type}/{id}/links/{field} with {add, remove} -- atomic link merge.
1375
- * Dedupes, tolerates already-present/already-absent ids. Returns the FULL
1376
- * updated element (fixture P5). Use this for all relationship editing; it
1377
- * retires the read-merge-PATCH dance.
1378
- */
1379
- async editLinks(type, id, field, edit) {
1380
- return this.request("POST", `/${type}/${id}/links/${field}`, { body: edit });
1381
- }
1382
- // -- Bulk ----------------------------------------------------------------
1383
- /**
1384
- * POST /bulk -- up to ~1000 items. Partial success by default (HTTP 200
1385
- * always; inspect per-slot numeric `status` + top-level `errors` flag);
1386
- * atomic:true for all-or-nothing. Link validation runs against batch U
1387
- * database -- send in any order, cycles included; no client topo-sort.
1388
- * Success slots echo server-authoritative timestamps: set your sync baseline
1389
- * from this response alone. When an idempotencyKey is replayed, the returned
1390
- * response carries wasReplay:true (read from the Idempotent-Replay header).
1391
- */
1392
- async bulk(items, opts = {}) {
1393
- const body = {
1394
- items: items.map((it) => ({ type: it.type, element: sanitizePayload(it.element) })),
1395
- atomic: opts.atomic ?? false
1396
- };
1397
- return this.request("POST", "/bulk/", {
1398
- body,
1399
- idempotencyKey: opts.idempotencyKey,
1400
- replayAware: true
1401
- });
1402
- }
1403
- // -- Changes feed --------------------------------------------------------
1404
- /**
1405
- * GET /changes -- one page of the world's ordered change feed.
1406
- * Cursor is OPAQUE and never expires: persist verbatim, never parse.
1407
- * Zero/absent cursor = full export (byte-aligned with the Folder Format).
1408
- * Rewind rule: if your persisted position is ahead of page.head, the server
1409
- * was restored -- re-baseline from cursor zero; do not assume caught-up.
1410
- * Citizenship: heaviest route on the platform; default page size is polite.
1411
- */
1412
- async changes(opts = {}) {
1413
- const query = buildQuery({ since: opts.since, limit: opts.limit ?? this.changesPageSize });
1414
- return this.request("GET", "/changes/", { query });
1415
- }
1416
- /**
1417
- * Walk the feed from `since` (or from zero = full export) to the current
1418
- * tail, yielding ops in order. Returns the final cursor via the generator's
1419
- * return value; persist it for the next incremental pull.
1420
- */
1421
- async *changesAll(since) {
1422
- let cursor = since;
1423
- let page;
1424
- do {
1425
- page = await this.changes({ since: cursor });
1426
- for (const op of page.changes) yield op;
1427
- cursor = page.cursor;
1428
- } while (page.has_more);
1429
- return { cursor: page.cursor, head: page.head };
1430
- }
1431
- // -- Core request machinery ----------------------------------------------
1432
- async request(method, path, opts = {}) {
1433
- const url = `${this.baseUrl}${path}${opts.query ? `?${opts.query}` : ""}`;
1434
- const headers = {};
1435
- if (opts.auth !== false) {
1436
- if (this.keyKind === "account") {
1437
- headers["Authorization"] = `Bearer ${this.apiKey}`;
1438
- } else {
1439
- headers["API-Key"] = this.apiKey;
1440
- if (this.apiPin) headers["API-Pin"] = this.apiPin;
1441
- }
1442
- }
1443
- if (opts.body !== void 0) headers["Content-Type"] = "application/json";
1444
- if (opts.idempotencyKey) headers["Idempotency-Key"] = opts.idempotencyKey;
1445
- let res;
1446
- try {
1447
- res = await this.fetchImpl(url, {
1448
- method,
1449
- headers,
1450
- body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0
1451
- });
1452
- } catch (cause) {
1453
- throw new OwNetworkError(`OnlyWorlds request failed: ${method} ${path}`, cause);
1454
- }
1455
- if (!res.ok) throw await errorFromResponse(res);
1456
- if (res.status === 204 || opts.allowEmpty) {
1457
- const text = await res.text();
1458
- return text ? JSON.parse(text) : null;
1459
- }
1460
- const parsed = await res.json();
1461
- if (opts.replayAware && parsed && typeof parsed === "object") {
1462
- parsed.wasReplay = readReplayHeader(res.headers);
1463
- }
1464
- return parsed;
1465
- }
1466
- };
1467
- var READ_ONLY_FIELDS = ["world", "type", "created_at", "updated_at", "change_seq"];
1468
- function sanitizePayload(payload) {
1469
- if (!payload || typeof payload !== "object") return payload;
1470
- const rest = { ...payload };
1471
- for (const field of READ_ONLY_FIELDS) delete rest[field];
1472
- return rest;
1473
- }
1474
- function readReplayHeader(headers) {
1475
- const v = headers.get("Idempotent-Replay");
1476
- return v != null && v.toLowerCase() === "true";
1477
- }
1478
- function mintUuid() {
1479
- const c = globalThis.crypto;
1480
- if (c && typeof c.randomUUID === "function") return c.randomUUID();
1481
- const bytes = new Uint8Array(16);
1482
- if (c && typeof c.getRandomValues === "function") {
1483
- c.getRandomValues(bytes);
1484
- } else {
1485
- for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);
1486
- }
1487
- bytes[6] = bytes[6] & 15 | 64;
1488
- bytes[8] = bytes[8] & 63 | 128;
1489
- const hex = [];
1490
- for (let i = 0; i < 256; i++) hex.push((i + 256).toString(16).slice(1));
1491
- return hex[bytes[0]] + hex[bytes[1]] + hex[bytes[2]] + hex[bytes[3]] + "-" + hex[bytes[4]] + hex[bytes[5]] + "-" + hex[bytes[6]] + hex[bytes[7]] + "-" + hex[bytes[8]] + hex[bytes[9]] + "-" + hex[bytes[10]] + hex[bytes[11]] + hex[bytes[12]] + hex[bytes[13]] + hex[bytes[14]] + hex[bytes[15]];
1492
- }
1493
- function buildQuery(params) {
1494
- const q = new URLSearchParams();
1495
- for (const [k, v] of Object.entries(params)) {
1496
- if (v !== void 0 && v !== null && v !== "") q.set(k, String(v));
1497
- }
1498
- return q.toString();
1499
- }
1500
-
1501
- // src/v2/types.generated.ts
1502
- var ELEMENT_TYPES = ["ability", "character", "collective", "construct", "creature", "event", "family", "institution", "language", "law", "location", "map", "marker", "narrative", "object", "phenomenon", "pin", "relation", "species", "title", "trait", "zone"];
1503
- var ELEMENT_FAMILIES = {
1504
- ability: "abstract",
1505
- character: "agents",
1506
- collective: "agents",
1507
- construct: "world",
1508
- creature: "agents",
1509
- event: "temporal",
1510
- family: "agents",
1511
- institution: "agents",
1512
- language: "abstract",
1513
- law: "abstract",
1514
- location: "world",
1515
- map: "world",
1516
- marker: "world",
1517
- narrative: "temporal",
1518
- object: "world",
1519
- phenomenon: "temporal",
1520
- pin: "world",
1521
- relation: "temporal",
1522
- species: "agents",
1523
- title: "abstract",
1524
- trait: "abstract",
1525
- zone: "world"
1526
- };
1527
-
1528
- // src/v2/types.ts
1529
- var SPATIAL_TYPES = ["map", "pin", "marker", "zone"];
1530
-
1531
- // src/v2/palette.ts
1532
- var FAMILY_COLORS = {
1533
- agents: { light: "#2a78d6", dark: "#3987e5" },
1534
- world: { light: "#008300", dark: "#008300" },
1535
- abstract: { light: "#e87ba4", dark: "#d55181" },
1536
- temporal: { light: "#eda100", dark: "#c98500" }
1537
- };
1538
- function familyOf(type) {
1539
- return ELEMENT_FAMILIES[type];
1540
- }
1541
- function elementColor(type, mode = "dark") {
1542
- return FAMILY_COLORS[ELEMENT_FAMILIES[type]][mode];
1543
- }
1544
- var FAMILY_ORDER = ["agents", "world", "abstract", "temporal"];
1545
- export {
1546
- ELEMENT_FAMILIES,
1547
- ELEMENT_ICONS,
1548
- ELEMENT_LABELS,
1549
- ELEMENT_SECTIONS,
1550
- ELEMENT_TYPES,
1551
- ElementType,
1552
- FAMILY_COLORS,
1553
- FAMILY_ORDER,
1554
- FIELD_SCHEMA,
1555
- GameTier,
1556
- ONLYWORLDS_VERSION,
1557
- OnlyWorldsClient,
1558
- OwApiError,
1559
- OwNetworkError,
1560
- OwV2Client,
1561
- SPATIAL_TYPES,
1562
- createAnyElementId,
1563
- createElementId,
1564
- createElementIds,
1565
- detectKeyKind,
1566
- elementColor,
1567
- errorFromResponse,
1568
- familyOf,
1569
- getElementIcon,
1570
- getElementLabel,
1571
- getElementSections,
1572
- isDemoKey,
1573
- kindCanWrite,
1574
- parseEnvelope,
1575
- pinExpectation
1576
- };