@roblawn/devtool-runtime 0.1.0-alpha.0 → 0.1.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.
Files changed (56) hide show
  1. package/LICENSE.md +11 -11
  2. package/README.md +7 -7
  3. package/dist/content/envelope.d.ts +54 -0
  4. package/dist/content/envelope.js +10 -0
  5. package/dist/content/envelopeResolver.d.ts +14 -0
  6. package/dist/content/envelopeResolver.js +77 -0
  7. package/dist/content/identity.d.ts +16 -0
  8. package/dist/content/identity.js +1 -0
  9. package/dist/content/index.d.ts +10 -0
  10. package/dist/content/index.js +10 -0
  11. package/dist/content/normalize.d.ts +8 -0
  12. package/dist/content/normalize.js +53 -0
  13. package/dist/content/profile.d.ts +11 -0
  14. package/dist/content/profile.js +29 -0
  15. package/dist/content/provider.d.ts +17 -0
  16. package/dist/content/provider.js +1 -0
  17. package/dist/content/safeContent.d.ts +2 -0
  18. package/dist/content/safeContent.js +44 -0
  19. package/dist/content/scope.d.ts +6 -0
  20. package/dist/content/scope.js +41 -0
  21. package/dist/content/slotItems.d.ts +13 -0
  22. package/dist/content/slotItems.js +53 -0
  23. package/dist/content/targets.d.ts +24 -0
  24. package/dist/content/targets.js +9 -0
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.js +1 -0
  27. package/dist/schema/LayoutDefinitionMeta.d.ts +6 -0
  28. package/dist/shared/legacyNames.d.ts +6 -0
  29. package/dist/shared/legacyNames.js +8 -0
  30. package/dist/static/buildSsg.d.ts +11 -0
  31. package/dist/static/buildSsg.js +93 -0
  32. package/dist/static/index.d.ts +4 -0
  33. package/dist/static/index.js +4 -0
  34. package/dist/static/packageNetlify.d.ts +28 -0
  35. package/dist/static/packageNetlify.js +141 -0
  36. package/dist/static/packageStaticSite.d.ts +19 -0
  37. package/dist/static/packageStaticSite.js +144 -0
  38. package/dist/static/serveStaticSite.d.ts +9 -0
  39. package/dist/static/serveStaticSite.js +143 -0
  40. package/dist/theme-contract/ops/coreOps.js +5 -47
  41. package/dist/theme-contract/ops/emitters.d.ts +2 -0
  42. package/dist/theme-contract/ops/emitters.js +38 -2
  43. package/dist/theme-contract/tokens/schemas/spacing.token.schema.d.ts +9 -2
  44. package/dist/theme-contract/tokens/schemas/spacing.token.schema.js +9 -2
  45. package/dist/theme-contract/tokens/tokens.schema.d.ts +9 -2
  46. package/dist/vite/embeddedJsonPlugin.d.ts +8 -0
  47. package/dist/vite/embeddedJsonPlugin.js +109 -0
  48. package/dist/vite/index.d.ts +4 -0
  49. package/dist/vite/index.js +4 -0
  50. package/dist/vite/localJsonPlugin.d.ts +4 -0
  51. package/dist/vite/localJsonPlugin.js +70 -0
  52. package/dist/vite/ssgEntryPlugin.d.ts +7 -0
  53. package/dist/vite/ssgEntryPlugin.js +21 -0
  54. package/dist/vite/staticFallbackPlugin.d.ts +8 -0
  55. package/dist/vite/staticFallbackPlugin.js +77 -0
  56. package/package.json +47 -27
package/LICENSE.md CHANGED
@@ -1,11 +1,11 @@
1
- Proprietary Alpha License
2
-
3
- Copyright (c) 2026 Rob Lawn. All rights reserved.
4
-
5
- Permission is granted to install and use this package as a runtime dependency of generated visual site authoring projects.
6
-
7
- This package is proprietary. No ownership or copyright interest is transferred. You may not redistribute, resell, sublicense, or repackage this package as a competing runtime, framework, scaffold, starter, or component product without prior written permission.
8
-
9
- This software is provided "as is", without warranty of any kind, express or implied, including but not limited to warranties of merchantability, fitness for a particular purpose, non-infringement, availability, security, or correctness. Use is at your own risk.
10
-
11
- In no event shall the copyright holder or contributors be liable for any claim, damages, data loss, business interruption, or other liability arising from use of this software.
1
+ Proprietary Alpha License
2
+
3
+ Copyright (c) 2026 Rob Lawn. All rights reserved.
4
+
5
+ Permission is granted to install and use this package as a runtime dependency of generated visual site authoring projects.
6
+
7
+ This package is proprietary. No ownership or copyright interest is transferred. You may not redistribute, resell, sublicense, or repackage this package as a competing runtime, framework, scaffold, starter, or component product without prior written permission.
8
+
9
+ This software is provided "as is", without warranty of any kind, express or implied, including but not limited to warranties of merchantability, fitness for a particular purpose, non-infringement, availability, security, or correctness. Use is at your own risk.
10
+
11
+ In no event shall the copyright holder or contributors be liable for any claim, damages, data loss, business interruption, or other liability arising from use of this software.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
- # @roblawn/devtool-runtime
2
-
3
- Alpha runtime primitives for generated visual site authoring projects.
4
-
5
- This package is intended to be installed by a compatible starter creator and consumed by generated sites.
6
-
7
- This package is proprietary alpha software, supplied as-is. See `LICENSE.md`.
1
+ # @roblawn/devtool-runtime
2
+
3
+ Alpha runtime primitives for generated visual site authoring projects.
4
+
5
+ This package is intended to be installed by a compatible starter creator and consumed by generated sites.
6
+
7
+ This package is proprietary alpha software, supplied as-is. See `LICENSE.md`.
@@ -0,0 +1,54 @@
1
+ import type { ContentProviderName, ContentTarget } from './targets.js';
2
+ export declare const CONTENT_CONTRACT_VERSION: "published-content.v1";
3
+ export type ContentContractVersion = typeof CONTENT_CONTRACT_VERSION;
4
+ export type ContentBag = Record<string, unknown>;
5
+ export interface ContentEnvelope {
6
+ contractVersion: ContentContractVersion;
7
+ target: ContentTarget;
8
+ scope: string;
9
+ content: ContentBag;
10
+ items?: SlotItem[];
11
+ meta?: ContentEnvelopeMeta;
12
+ }
13
+ export interface ContentEnvelopeMeta {
14
+ templateDir?: string;
15
+ provider?: ContentProviderName;
16
+ providerId?: string;
17
+ etag?: string;
18
+ [key: string]: unknown;
19
+ }
20
+ export type LoadState = 'idle' | 'loading' | 'ready' | 'error';
21
+ export type SlotItem = BlockSlotItem | ModuleSlotItem | CustomSlotItem;
22
+ export interface BlockSlotItem {
23
+ kind: 'block';
24
+ key?: string;
25
+ type: string;
26
+ props?: Record<string, unknown>;
27
+ layout?: Record<string, unknown>;
28
+ scope?: string;
29
+ providerId?: string;
30
+ providerKey?: string;
31
+ }
32
+ export interface ModuleSlotItem {
33
+ kind: 'module';
34
+ key?: string;
35
+ type?: string;
36
+ subType: string;
37
+ slug: string;
38
+ instance?: string;
39
+ instanceId?: string;
40
+ scope: string;
41
+ providerId?: string;
42
+ providerKey?: string;
43
+ }
44
+ export interface CustomSlotItem {
45
+ key: string;
46
+ kind?: string;
47
+ type: string;
48
+ props?: Record<string, unknown>;
49
+ scope?: string;
50
+ instance?: string;
51
+ providerId?: string;
52
+ providerKey?: string;
53
+ }
54
+ export declare function createContentEnvelope(input: Omit<ContentEnvelope, 'contractVersion'>): ContentEnvelope;
@@ -0,0 +1,10 @@
1
+ export const CONTENT_CONTRACT_VERSION = 'published-content.v1';
2
+ export function createContentEnvelope(input) {
3
+ return {
4
+ contractVersion: CONTENT_CONTRACT_VERSION,
5
+ ...input,
6
+ content: { ...input.content },
7
+ items: input.items ? input.items.map((item) => ({ ...item })) : undefined,
8
+ meta: input.meta ? { ...input.meta } : undefined,
9
+ };
10
+ }
@@ -0,0 +1,14 @@
1
+ import { type ContentEnvelope } from './envelope.js';
2
+ import type { ContentTarget } from './targets.js';
3
+ export type ContentStash = Record<string, ContentEnvelope>;
4
+ type ContentGlobal = {
5
+ window?: Record<string, ContentStash | undefined>;
6
+ };
7
+ export declare function contentTargetKey(target: ContentTarget): string;
8
+ export declare function getContentStash(root?: ContentGlobal, stashKey?: string): ContentStash;
9
+ export declare function setContentStashEntry(key: string, envelope: ContentEnvelope, root?: ContentGlobal, stashKey?: string): void;
10
+ export declare function templateDirForSlug(slug: string): string;
11
+ export declare function fallbackScope(target: ContentTarget): string;
12
+ export declare function coerceContentEnvelope(json: unknown, target: ContentTarget, scope?: string, meta?: Record<string, unknown>): ContentEnvelope;
13
+ export declare function isContentTarget(value: unknown): value is ContentTarget;
14
+ export {};
@@ -0,0 +1,77 @@
1
+ import { createContentEnvelope } from './envelope.js';
2
+ import { createModuleScope, createPageScope } from './scope.js';
3
+ export function contentTargetKey(target) {
4
+ if (target.kind === 'page')
5
+ return `page:${target.slug}`;
6
+ if (target.kind === 'global')
7
+ return `global:${target.slug}:${target.scope ?? ''}`;
8
+ return [
9
+ 'module',
10
+ target.subType,
11
+ target.slug,
12
+ target.instance ?? '',
13
+ target.scope ?? '',
14
+ target.providerId ?? '',
15
+ ].join(':');
16
+ }
17
+ export function getContentStash(root = globalThis, stashKey = '__CONTENT_STASH__') {
18
+ return root.window?.[stashKey] ?? {};
19
+ }
20
+ export function setContentStashEntry(key, envelope, root = globalThis, stashKey = '__CONTENT_STASH__') {
21
+ if (!root.window)
22
+ return;
23
+ root.window[stashKey] = {
24
+ ...(root.window[stashKey] ?? {}),
25
+ [key]: envelope,
26
+ };
27
+ }
28
+ export function templateDirForSlug(slug) {
29
+ return slug
30
+ .trim()
31
+ .toLowerCase()
32
+ .replace(/[^a-z0-9]+/g, '-')
33
+ .replace(/^-+|-+$/g, '');
34
+ }
35
+ export function fallbackScope(target) {
36
+ if (target.kind === 'page')
37
+ return createPageScope(target.slug);
38
+ if (target.kind === 'module') {
39
+ return target.scope ?? createModuleScope(target.subType, target.slug, target.instance);
40
+ }
41
+ return target.scope ?? `global_${target.slug}`;
42
+ }
43
+ export function coerceContentEnvelope(json, target, scope = fallbackScope(target), meta = {}) {
44
+ if (isRecord(json) && isRecord(json.content)) {
45
+ return createContentEnvelope({
46
+ target: isContentTarget(json.target) ? json.target : target,
47
+ scope: typeof json.scope === 'string' ? json.scope : scope,
48
+ content: json.content,
49
+ items: Array.isArray(json.items) ? json.items : [],
50
+ meta: {
51
+ ...meta,
52
+ ...(isRecord(json.meta) ? json.meta : {}),
53
+ ...(typeof json.contractVersion === 'string' ? { contractVersion: json.contractVersion } : {}),
54
+ ...(Array.isArray(json.entries) ? { entries: json.entries } : {}),
55
+ },
56
+ });
57
+ }
58
+ return createContentEnvelope({
59
+ target,
60
+ scope,
61
+ content: isRecord(json) ? json : {},
62
+ items: [],
63
+ meta,
64
+ });
65
+ }
66
+ export function isContentTarget(value) {
67
+ if (!isRecord(value) || typeof value.kind !== 'string')
68
+ return false;
69
+ if (value.kind === 'page')
70
+ return typeof value.slug === 'string';
71
+ if (value.kind === 'global')
72
+ return typeof value.slug === 'string';
73
+ return value.kind === 'module' && typeof value.subType === 'string' && typeof value.slug === 'string';
74
+ }
75
+ function isRecord(value) {
76
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
77
+ }
@@ -0,0 +1,16 @@
1
+ export type ContentKey = string;
2
+ export type SlotKey = string;
3
+ export type ContentScope = string;
4
+ export type ProviderId = string;
5
+ export type ProviderKey = string;
6
+ export type AuthoringStableId = string;
7
+ export interface ProviderIdentity {
8
+ providerId?: ProviderId;
9
+ providerKey?: ProviderKey;
10
+ }
11
+ export interface ContentIdentity extends ProviderIdentity {
12
+ contentKey: ContentKey;
13
+ scope?: ContentScope;
14
+ instance?: string;
15
+ stableId?: AuthoringStableId;
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ export * from './targets.js';
2
+ export * from './envelope.js';
3
+ export * from './identity.js';
4
+ export * from './scope.js';
5
+ export * from './provider.js';
6
+ export * from './normalize.js';
7
+ export * from './profile.js';
8
+ export * from './safeContent.js';
9
+ export * from './slotItems.js';
10
+ export * from './envelopeResolver.js';
@@ -0,0 +1,10 @@
1
+ export * from './targets.js';
2
+ export * from './envelope.js';
3
+ export * from './identity.js';
4
+ export * from './scope.js';
5
+ export * from './provider.js';
6
+ export * from './normalize.js';
7
+ export * from './profile.js';
8
+ export * from './safeContent.js';
9
+ export * from './slotItems.js';
10
+ export * from './envelopeResolver.js';
@@ -0,0 +1,8 @@
1
+ import { type ContentEnvelope } from './envelope.js';
2
+ import type { ContentTarget } from './targets.js';
3
+ export interface NormalizeContentEnvelopeOptions {
4
+ target: ContentTarget;
5
+ scope: string;
6
+ }
7
+ export declare function normalizeContentEnvelope(value: unknown, options: NormalizeContentEnvelopeOptions): ContentEnvelope;
8
+ export declare function isContentEnvelope(value: unknown): value is ContentEnvelope;
@@ -0,0 +1,53 @@
1
+ import { CONTENT_CONTRACT_VERSION } from './envelope.js';
2
+ const LEGACY_CONTENT_CONTRACT_VERSION = ['tun', 'dra.published-content.v1'].join('');
3
+ export function normalizeContentEnvelope(value, options) {
4
+ if (isContentEnvelope(value)) {
5
+ return {
6
+ contractVersion: CONTENT_CONTRACT_VERSION,
7
+ target: value.target,
8
+ scope: value.scope,
9
+ content: cloneRecord(value.content),
10
+ items: Array.isArray(value.items) ? value.items.map(cloneSlotItem) : undefined,
11
+ meta: isRecord(value.meta) ? cloneRecord(value.meta) : undefined,
12
+ };
13
+ }
14
+ if (isRecord(value)) {
15
+ return {
16
+ contractVersion: CONTENT_CONTRACT_VERSION,
17
+ target: options.target,
18
+ scope: options.scope,
19
+ content: cloneRecord(value),
20
+ };
21
+ }
22
+ throw new Error('Content envelope must be an object.');
23
+ }
24
+ export function isContentEnvelope(value) {
25
+ if (!isRecord(value))
26
+ return false;
27
+ if (value.contractVersion !== CONTENT_CONTRACT_VERSION &&
28
+ value.contractVersion !== LEGACY_CONTENT_CONTRACT_VERSION) {
29
+ return false;
30
+ }
31
+ if (!isRecord(value.target))
32
+ return false;
33
+ if (typeof value.scope !== 'string')
34
+ return false;
35
+ if (!isRecord(value.content))
36
+ return false;
37
+ return true;
38
+ }
39
+ function cloneRecord(value) {
40
+ return { ...value };
41
+ }
42
+ function cloneSlotItem(item) {
43
+ if ('props' in item) {
44
+ return {
45
+ ...item,
46
+ props: item.props ? { ...item.props } : undefined,
47
+ };
48
+ }
49
+ return { ...item };
50
+ }
51
+ function isRecord(value) {
52
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
53
+ }
@@ -0,0 +1,11 @@
1
+ export type ContentProfile = 'local' | 'embedded-json' | 'cms';
2
+ export interface ResolveContentProfileOptions {
3
+ env?: Record<string, string | undefined>;
4
+ override?: string;
5
+ mode?: string;
6
+ }
7
+ export declare function resolveContentProfile(options?: ResolveContentProfileOptions): ContentProfile;
8
+ export declare function isCmsProfile(profile: ContentProfile): boolean;
9
+ export declare function localBasePrefix(profile: ContentProfile): string;
10
+ export declare function localPageUrl(slug: string, profile: ContentProfile): string;
11
+ export declare function localModuleUrls(subType: string, slug: string, profile: ContentProfile, instance?: string): string[];
@@ -0,0 +1,29 @@
1
+ const LEGACY_NAME = ['TUN', 'DRA'].join('');
2
+ const LOCAL_PRIVATE_BASE = `/.${LEGACY_NAME.toLowerCase()}`;
3
+ const LOCAL_PUBLIC_BASE = `/__${LEGACY_NAME.toLowerCase()}`;
4
+ export function resolveContentProfile(options = {}) {
5
+ const env = options.env ?? {};
6
+ const raw = options.override ??
7
+ env.VITE_DEVTOOL_CONTENT_PROFILE ??
8
+ env[`VITE_${LEGACY_NAME}_CONTENT_PROFILE`] ??
9
+ (options.mode === 'preview' || options.mode === 'ssg' ? 'embedded-json' : 'local');
10
+ if (raw === 'cms' || raw === 'embedded-json' || raw === 'local')
11
+ return raw;
12
+ return 'local';
13
+ }
14
+ export function isCmsProfile(profile) {
15
+ return profile === 'cms';
16
+ }
17
+ export function localBasePrefix(profile) {
18
+ return profile === 'embedded-json' ? LOCAL_PUBLIC_BASE : LOCAL_PRIVATE_BASE;
19
+ }
20
+ export function localPageUrl(slug, profile) {
21
+ const safe = slug.replace(/^\/+|\/+$/g, '');
22
+ return `${localBasePrefix(profile)}/pages/${encodeURIComponent(safe)}/content.json`;
23
+ }
24
+ export function localModuleUrls(subType, slug, profile, instance) {
25
+ const root = `${localBasePrefix(profile)}/modules/${encodeURIComponent(subType)}/${encodeURIComponent(slug)}`;
26
+ return instance
27
+ ? [`${root}/${encodeURIComponent(instance)}/content.json`, `${root}/content.json`]
28
+ : [`${root}/content.json`];
29
+ }
@@ -0,0 +1,17 @@
1
+ import type { ContentEnvelope } from './envelope.js';
2
+ import type { ContentProviderName, ContentTarget } from './targets.js';
3
+ export interface ContentReadProvider {
4
+ name: ContentProviderName;
5
+ resolve(target: ContentTarget): Promise<ContentEnvelope>;
6
+ }
7
+ export interface ContentWriteProvider {
8
+ name: ContentProviderName;
9
+ write(envelope: ContentEnvelope): Promise<ContentWriteResult>;
10
+ }
11
+ export interface ContentWriteResult {
12
+ target: ContentTarget;
13
+ status: ContentWriteStatus;
14
+ providerId?: string;
15
+ warnings?: string[];
16
+ }
17
+ export type ContentWriteStatus = 'created' | 'updated' | 'unchanged' | 'skipped' | 'failed';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export type ContentMap = Record<string, unknown>;
2
+ export declare function makeSafeContentProxy<TContentMap extends ContentMap>(src: TContentMap): TContentMap;
@@ -0,0 +1,44 @@
1
+ import { markRaw } from 'vue';
2
+ const emptyArray = Object.freeze([]);
3
+ const hasOwn = Object.prototype.hasOwnProperty;
4
+ function isRecord(value) {
5
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
6
+ }
7
+ function makeSafeContentValue(value) {
8
+ if (Array.isArray(value))
9
+ return value.map(makeSafeContentValue);
10
+ if (isRecord(value))
11
+ return makeSafeContentProxy(value);
12
+ return value;
13
+ }
14
+ export function makeSafeContentProxy(src) {
15
+ const handler = {
16
+ get(target, prop, receiver) {
17
+ if (hasOwn.call(target, prop)) {
18
+ const value = Reflect.get(target, prop, receiver);
19
+ if (value !== undefined)
20
+ return makeSafeContentValue(value);
21
+ }
22
+ if (prop === 'length')
23
+ return 0;
24
+ if (prop === Symbol.iterator)
25
+ return emptyArray[Symbol.iterator].bind(emptyArray);
26
+ if (prop === Symbol.toPrimitive)
27
+ return () => '';
28
+ if (prop === 'toString')
29
+ return () => '';
30
+ if (prop === 'valueOf')
31
+ return () => '';
32
+ if (typeof prop === 'string' && prop.startsWith('__v_'))
33
+ return undefined;
34
+ if (typeof prop === 'string' && prop in emptyArray) {
35
+ const arrayValue = emptyArray[prop];
36
+ return typeof arrayValue === 'function' ? arrayValue.bind(emptyArray) : arrayValue;
37
+ }
38
+ if (typeof prop === 'string' && prop.startsWith('slot_'))
39
+ return [];
40
+ return makeSafeContentProxy({});
41
+ },
42
+ };
43
+ return markRaw(new Proxy({ ...src }, handler));
44
+ }
@@ -0,0 +1,6 @@
1
+ import type { ContentBag } from './envelope.js';
2
+ export declare function scopeSegment(value: string): string;
3
+ export declare function createPageScope(slug: string): string;
4
+ export declare function createModuleScope(subType: string, slug: string, instance?: string): string;
5
+ export declare function scopedContentKey(scope: string, key: string): string;
6
+ export declare function descopeContent<TContent extends ContentBag = ContentBag>(content: ContentBag, scope: string): TContent;
@@ -0,0 +1,41 @@
1
+ export function scopeSegment(value) {
2
+ return value
3
+ .trim()
4
+ .toLowerCase()
5
+ .replace(/[^a-z0-9]+/g, '_')
6
+ .replace(/^_+|_+$/g, '');
7
+ }
8
+ export function createPageScope(slug) {
9
+ return `page_${scopeSegment(slug) || 'index'}`;
10
+ }
11
+ export function createModuleScope(subType, slug, instance) {
12
+ const base = ['module', scopeSegment(subType), scopeSegment(slug)].filter(Boolean).join('_');
13
+ const suffix = instance ? `_${scopeSegment(instance)}` : '';
14
+ return `${base || 'module'}${suffix}`;
15
+ }
16
+ export function scopedContentKey(scope, key) {
17
+ return `${scope}::${key}`;
18
+ }
19
+ function legacyScopedBlockAlias(key) {
20
+ const match = /^block_[A-Za-z][A-Za-z0-9]*_(.+)$/.exec(key);
21
+ return match?.[1];
22
+ }
23
+ export function descopeContent(content, scope) {
24
+ const prefix = `${scope}::`;
25
+ const result = {};
26
+ for (const [key, value] of Object.entries(content)) {
27
+ if (key.startsWith(prefix)) {
28
+ const localKey = key.slice(prefix.length);
29
+ result[localKey] = value;
30
+ const alias = legacyScopedBlockAlias(localKey);
31
+ if (alias && !(alias in result)) {
32
+ result[alias] = value;
33
+ }
34
+ continue;
35
+ }
36
+ if (!key.includes('::')) {
37
+ result[key] = value;
38
+ }
39
+ }
40
+ return result;
41
+ }
@@ -0,0 +1,13 @@
1
+ import type { ContentBag, SlotItem } from './envelope.js';
2
+ export type LayoutFallbacks = Record<string, Record<string, unknown>>;
3
+ export type ResolvedSlotItem = SlotItem & {
4
+ props?: Record<string, unknown>;
5
+ layout?: Record<string, unknown>;
6
+ };
7
+ export declare function slotItemKey(item: SlotItem, index: number): string;
8
+ export declare function moduleSlotRegistryKey(item: Extract<SlotItem, {
9
+ kind: 'module';
10
+ }>): string;
11
+ export declare function resolveSlotItems(items: SlotItem[] | null | undefined, pageContent?: ContentBag | null, layoutFallbacks?: LayoutFallbacks | null): ResolvedSlotItem[];
12
+ export declare function resolveSlotItem(item: SlotItem, pageContent?: ContentBag | null, layoutFallbacks?: LayoutFallbacks | null): ResolvedSlotItem;
13
+ export declare function slotItemRenderProps(item: ResolvedSlotItem): Record<string, unknown>;
@@ -0,0 +1,53 @@
1
+ import { descopeContent } from './scope.js';
2
+ export function slotItemKey(item, index) {
3
+ if (isModuleSlotItem(item)) {
4
+ return `${item.subType}/${item.slug}@${item.instanceId ?? item.instance ?? index}`;
5
+ }
6
+ const props = isRecord(item.props) ? item.props : {};
7
+ const key = item.key ?? props._key;
8
+ return typeof key === 'string' && key.length > 0 ? `${item.type}@${key}` : `${item.type}#${index}`;
9
+ }
10
+ export function moduleSlotRegistryKey(item) {
11
+ return `${item.subType}/${item.slug}`.toLowerCase();
12
+ }
13
+ export function resolveSlotItems(items, pageContent, layoutFallbacks) {
14
+ if (!Array.isArray(items))
15
+ return [];
16
+ return items.map((item) => resolveSlotItem(item, pageContent, layoutFallbacks));
17
+ }
18
+ export function resolveSlotItem(item, pageContent, layoutFallbacks) {
19
+ if (isModuleSlotItem(item)) {
20
+ const existingProps = optionalRecord(item, 'props');
21
+ return {
22
+ ...item,
23
+ props: item.scope && pageContent ? descopeContent(pageContent, item.scope) : existingProps ?? {},
24
+ };
25
+ }
26
+ const existingLayout = optionalRecord(item, 'layout');
27
+ return {
28
+ ...item,
29
+ props: item.props ?? {},
30
+ layout: existingLayout ?? layoutFallbacks?.[item.type] ?? {},
31
+ };
32
+ }
33
+ export function slotItemRenderProps(item) {
34
+ if (isModuleSlotItem(item)) {
35
+ return { content: item.props ?? {} };
36
+ }
37
+ return {
38
+ content: item.props ?? {},
39
+ layout: item.layout ?? {},
40
+ };
41
+ }
42
+ function isModuleSlotItem(item) {
43
+ return item.kind === 'module';
44
+ }
45
+ function isRecord(value) {
46
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
47
+ }
48
+ function optionalRecord(value, key) {
49
+ if (!isRecord(value))
50
+ return undefined;
51
+ const candidate = value[key];
52
+ return isRecord(candidate) ? candidate : undefined;
53
+ }
@@ -0,0 +1,24 @@
1
+ export type ContentTargetKind = 'page' | 'module' | 'global';
2
+ export type ContentProviderName = 'local-json' | 'sanity' | 'custom';
3
+ export type ContentTarget = PageContentTarget | ModuleContentTarget | GlobalContentTarget;
4
+ export interface PageContentTarget {
5
+ kind: 'page';
6
+ slug: string;
7
+ }
8
+ export interface ModuleContentTarget {
9
+ kind: 'module';
10
+ subType: string;
11
+ slug: string;
12
+ instance?: string;
13
+ scope?: string;
14
+ providerId?: string;
15
+ }
16
+ export interface GlobalContentTarget {
17
+ kind: 'global';
18
+ slug: string;
19
+ scope?: string;
20
+ providerId?: string;
21
+ }
22
+ export declare function pageContentTarget(slug: string): PageContentTarget;
23
+ export declare function moduleContentTarget(input: Omit<ModuleContentTarget, 'kind'>): ModuleContentTarget;
24
+ export declare function globalContentTarget(input: Omit<GlobalContentTarget, 'kind'>): GlobalContentTarget;
@@ -0,0 +1,9 @@
1
+ export function pageContentTarget(slug) {
2
+ return { kind: 'page', slug };
3
+ }
4
+ export function moduleContentTarget(input) {
5
+ return { kind: 'module', ...input };
6
+ }
7
+ export function globalContentTarget(input) {
8
+ return { kind: 'global', ...input };
9
+ }
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './design-system/index.js';
2
+ export * from './content/index.js';
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
1
  export * from './design-system/index.js';
2
+ export * from './content/index.js';
@@ -1,6 +1,7 @@
1
1
  import type { BindingEditorPolicy } from './LayoutBindingEditorPolicyMetadata.js';
2
2
  import type { BindingEditorSection } from './LayoutBindingEditorSectionMetadata.js';
3
3
  import type { LayoutFieldUiMeta } from './LayoutFieldUiMetadata.js';
4
+ import type { AuthoringEffectKind } from '../authoring/index.js';
4
5
  export type LayoutFieldAuthoringNumberValue = {
5
6
  kind: 'number';
6
7
  min?: number;
@@ -10,11 +11,14 @@ export type LayoutFieldAuthoringNumberValue = {
10
11
  export type LayoutFieldAuthoringMeta = {
11
12
  sourceKind: 'coreToken';
12
13
  ops: string[];
14
+ tokenFamily?: string;
13
15
  surface: 'css' | 'responsive';
16
+ effectKinds?: AuthoringEffectKind[];
14
17
  } | {
15
18
  sourceKind: 'declaredToken';
16
19
  designOp?: string;
17
20
  tokenFamily?: string;
21
+ effectKinds?: AuthoringEffectKind[];
18
22
  } | {
19
23
  sourceKind: 'enum';
20
24
  } | {
@@ -28,11 +32,13 @@ export type LayoutFieldAuthoringMeta = {
28
32
  designOp?: string;
29
33
  tokenFamily?: string;
30
34
  surface?: 'css' | 'responsive';
35
+ effectKinds?: AuthoringEffectKind[];
31
36
  authoringValue?: LayoutFieldAuthoringNumberValue;
32
37
  } | {
33
38
  sourceKind: 'valueEnum';
34
39
  designOp?: string;
35
40
  tokenFamily?: string;
41
+ effectKinds?: AuthoringEffectKind[];
36
42
  } | {
37
43
  sourceKind: 'wrapper';
38
44
  } | {
@@ -0,0 +1,6 @@
1
+ export declare const LEGACY_NAME_LOWER: string;
2
+ export declare const LEGACY_NAME_UPPER: string;
3
+ export declare const LEGACY_PRIVATE_DIR: string;
4
+ export declare const LEGACY_PUBLIC_DIR: string;
5
+ export declare const LEGACY_CONFIG_FILE: string;
6
+ export declare function legacyContract(suffix: string): string;
@@ -0,0 +1,8 @@
1
+ export const LEGACY_NAME_LOWER = ['tun', 'dra'].join('');
2
+ export const LEGACY_NAME_UPPER = LEGACY_NAME_LOWER.toUpperCase();
3
+ export const LEGACY_PRIVATE_DIR = `.${LEGACY_NAME_LOWER}`;
4
+ export const LEGACY_PUBLIC_DIR = `__${LEGACY_NAME_LOWER}`;
5
+ export const LEGACY_CONFIG_FILE = `${LEGACY_NAME_LOWER}.json`;
6
+ export function legacyContract(suffix) {
7
+ return `${LEGACY_NAME_LOWER}.${suffix}`;
8
+ }
@@ -0,0 +1,11 @@
1
+ export type StaticSsgBuildArgs = {
2
+ configFile: string;
3
+ mode: string;
4
+ outDir: string;
5
+ };
6
+ export type StaticSsgBuildOptions = {
7
+ cwd?: string;
8
+ };
9
+ export declare function parseStaticSsgBuildArgs(argv: string[]): StaticSsgBuildArgs;
10
+ export declare function buildStaticSsg(args?: Partial<StaticSsgBuildArgs>, options?: StaticSsgBuildOptions): Promise<void>;
11
+ export declare function runStaticSsgBuildCli(argv?: string[]): Promise<void>;