emdash-emit 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +794 -2
  3. package/dist/bin/emit.d.ts +5 -0
  4. package/dist/bin/emit.d.ts.map +1 -0
  5. package/dist/bin/emit.js +62 -0
  6. package/dist/bin/emit.js.map +1 -0
  7. package/dist/cli/commands/new.d.ts +4 -0
  8. package/dist/cli/commands/new.d.ts.map +1 -0
  9. package/dist/cli/commands/new.js +48 -0
  10. package/dist/cli/commands/new.js.map +1 -0
  11. package/dist/cli/commands/profile.d.ts +3 -0
  12. package/dist/cli/commands/profile.d.ts.map +1 -0
  13. package/dist/cli/commands/profile.js +104 -0
  14. package/dist/cli/commands/profile.js.map +1 -0
  15. package/dist/cli/commands/pull.d.ts +4 -0
  16. package/dist/cli/commands/pull.d.ts.map +1 -0
  17. package/dist/cli/commands/pull.js +157 -0
  18. package/dist/cli/commands/pull.js.map +1 -0
  19. package/dist/cli/commands/push.d.ts +4 -0
  20. package/dist/cli/commands/push.d.ts.map +1 -0
  21. package/dist/cli/commands/push.js +107 -0
  22. package/dist/cli/commands/push.js.map +1 -0
  23. package/dist/cli/commands/status.d.ts +4 -0
  24. package/dist/cli/commands/status.d.ts.map +1 -0
  25. package/dist/cli/commands/status.js +100 -0
  26. package/dist/cli/commands/status.js.map +1 -0
  27. package/dist/cli/context.d.ts +15 -0
  28. package/dist/cli/context.d.ts.map +1 -0
  29. package/dist/cli/context.js +75 -0
  30. package/dist/cli/context.js.map +1 -0
  31. package/dist/client/api.d.ts +19 -0
  32. package/dist/client/api.d.ts.map +1 -0
  33. package/dist/client/api.js +96 -0
  34. package/dist/client/api.js.map +1 -0
  35. package/dist/client/auth.d.ts +48 -0
  36. package/dist/client/auth.d.ts.map +1 -0
  37. package/dist/client/auth.js +165 -0
  38. package/dist/client/auth.js.map +1 -0
  39. package/dist/client/error.d.ts +22 -0
  40. package/dist/client/error.d.ts.map +1 -0
  41. package/dist/client/error.js +57 -0
  42. package/dist/client/error.js.map +1 -0
  43. package/dist/client/http.d.ts +31 -0
  44. package/dist/client/http.d.ts.map +1 -0
  45. package/dist/client/http.js +97 -0
  46. package/dist/client/http.js.map +1 -0
  47. package/dist/client/lock.d.ts +40 -0
  48. package/dist/client/lock.d.ts.map +1 -0
  49. package/dist/client/lock.js +104 -0
  50. package/dist/client/lock.js.map +1 -0
  51. package/dist/client/mapper.d.ts +37 -0
  52. package/dist/client/mapper.d.ts.map +1 -0
  53. package/dist/client/mapper.js +134 -0
  54. package/dist/client/mapper.js.map +1 -0
  55. package/dist/client/portable-text.d.ts +94 -0
  56. package/dist/client/portable-text.d.ts.map +1 -0
  57. package/dist/client/portable-text.js +428 -0
  58. package/dist/client/portable-text.js.map +1 -0
  59. package/dist/client/schemas.d.ts +1928 -0
  60. package/dist/client/schemas.d.ts.map +1 -0
  61. package/dist/client/schemas.js +123 -0
  62. package/dist/client/schemas.js.map +1 -0
  63. package/dist/db/cache.d.ts +46 -0
  64. package/dist/db/cache.d.ts.map +1 -0
  65. package/dist/db/cache.js +230 -0
  66. package/dist/db/cache.js.map +1 -0
  67. package/dist/index.d.ts +23 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +44 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/mcp/context.d.ts +14 -0
  72. package/dist/mcp/context.d.ts.map +1 -0
  73. package/dist/mcp/context.js +23 -0
  74. package/dist/mcp/context.js.map +1 -0
  75. package/dist/mcp/server.d.ts +12 -0
  76. package/dist/mcp/server.d.ts.map +1 -0
  77. package/dist/mcp/server.js +105 -0
  78. package/dist/mcp/server.js.map +1 -0
  79. package/dist/mcp/tools/profile.d.ts +6 -0
  80. package/dist/mcp/tools/profile.d.ts.map +1 -0
  81. package/dist/mcp/tools/profile.js +81 -0
  82. package/dist/mcp/tools/profile.js.map +1 -0
  83. package/dist/mcp/tools/sync-diff.d.ts +4 -0
  84. package/dist/mcp/tools/sync-diff.d.ts.map +1 -0
  85. package/dist/mcp/tools/sync-diff.js +115 -0
  86. package/dist/mcp/tools/sync-diff.js.map +1 -0
  87. package/dist/mcp/tools/sync-new.d.ts +4 -0
  88. package/dist/mcp/tools/sync-new.d.ts.map +1 -0
  89. package/dist/mcp/tools/sync-new.js +54 -0
  90. package/dist/mcp/tools/sync-new.js.map +1 -0
  91. package/dist/mcp/tools/sync-pull.d.ts +4 -0
  92. package/dist/mcp/tools/sync-pull.d.ts.map +1 -0
  93. package/dist/mcp/tools/sync-pull.js +180 -0
  94. package/dist/mcp/tools/sync-pull.js.map +1 -0
  95. package/dist/mcp/tools/sync-push.d.ts +4 -0
  96. package/dist/mcp/tools/sync-push.d.ts.map +1 -0
  97. package/dist/mcp/tools/sync-push.js +105 -0
  98. package/dist/mcp/tools/sync-push.js.map +1 -0
  99. package/dist/mcp/tools/sync-status.d.ts +4 -0
  100. package/dist/mcp/tools/sync-status.d.ts.map +1 -0
  101. package/dist/mcp/tools/sync-status.js +45 -0
  102. package/dist/mcp/tools/sync-status.js.map +1 -0
  103. package/dist/sync/diff.d.ts +16 -0
  104. package/dist/sync/diff.d.ts.map +1 -0
  105. package/dist/sync/diff.js +68 -0
  106. package/dist/sync/diff.js.map +1 -0
  107. package/dist/sync/media.d.ts +37 -0
  108. package/dist/sync/media.d.ts.map +1 -0
  109. package/dist/sync/media.js +191 -0
  110. package/dist/sync/media.js.map +1 -0
  111. package/dist/sync/merge.d.ts +36 -0
  112. package/dist/sync/merge.d.ts.map +1 -0
  113. package/dist/sync/merge.js +112 -0
  114. package/dist/sync/merge.js.map +1 -0
  115. package/dist/sync/new.d.ts +21 -0
  116. package/dist/sync/new.d.ts.map +1 -0
  117. package/dist/sync/new.js +65 -0
  118. package/dist/sync/new.js.map +1 -0
  119. package/dist/sync/orchestrator.d.ts +55 -0
  120. package/dist/sync/orchestrator.d.ts.map +1 -0
  121. package/dist/sync/orchestrator.js +211 -0
  122. package/dist/sync/orchestrator.js.map +1 -0
  123. package/dist/sync/preflight.d.ts +25 -0
  124. package/dist/sync/preflight.d.ts.map +1 -0
  125. package/dist/sync/preflight.js +128 -0
  126. package/dist/sync/preflight.js.map +1 -0
  127. package/dist/sync/pull.d.ts +67 -0
  128. package/dist/sync/pull.d.ts.map +1 -0
  129. package/dist/sync/pull.js +382 -0
  130. package/dist/sync/pull.js.map +1 -0
  131. package/dist/sync/push.d.ts +33 -0
  132. package/dist/sync/push.d.ts.map +1 -0
  133. package/dist/sync/push.js +363 -0
  134. package/dist/sync/push.js.map +1 -0
  135. package/dist/sync/status.d.ts +24 -0
  136. package/dist/sync/status.d.ts.map +1 -0
  137. package/dist/sync/status.js +85 -0
  138. package/dist/sync/status.js.map +1 -0
  139. package/dist/sync/taxonomies.d.ts +49 -0
  140. package/dist/sync/taxonomies.d.ts.map +1 -0
  141. package/dist/sync/taxonomies.js +220 -0
  142. package/dist/sync/taxonomies.js.map +1 -0
  143. package/dist/utils/config.d.ts +18 -0
  144. package/dist/utils/config.d.ts.map +1 -0
  145. package/dist/utils/config.js +79 -0
  146. package/dist/utils/config.js.map +1 -0
  147. package/dist/utils/frontmatter.d.ts +115 -0
  148. package/dist/utils/frontmatter.d.ts.map +1 -0
  149. package/dist/utils/frontmatter.js +147 -0
  150. package/dist/utils/frontmatter.js.map +1 -0
  151. package/dist/utils/naming.d.ts +28 -0
  152. package/dist/utils/naming.d.ts.map +1 -0
  153. package/dist/utils/naming.js +94 -0
  154. package/dist/utils/naming.js.map +1 -0
  155. package/dist/utils/profile.d.ts +72 -0
  156. package/dist/utils/profile.d.ts.map +1 -0
  157. package/dist/utils/profile.js +180 -0
  158. package/dist/utils/profile.js.map +1 -0
  159. package/dist/utils/workspace.d.ts +22 -0
  160. package/dist/utils/workspace.d.ts.map +1 -0
  161. package/dist/utils/workspace.js +74 -0
  162. package/dist/utils/workspace.js.map +1 -0
  163. package/package.json +68 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/client/error.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;GAGG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjB,IAAI,CAAS;IACb,MAAM,CAAU;IAChB,UAAU,CAAU;IACpB,QAAQ,CAAU;IAElC,YAAY,OAMX;QACC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAEjC,+CAA+C;QAC/C,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED;;OAEG;IACI,kBAAkB;QACvB,MAAM,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,IAAI,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,mBAAmB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9D,IAAI,IAAI,CAAC,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/D,IAAI,IAAI,CAAC,UAAU;YAAE,KAAK,CAAC,IAAI,CAAC,qBAAqB,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QACxE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,31 @@
1
+ import { type ResolvedAuth } from './auth.js';
2
+ export interface AuthenticatedFetchOptions extends RequestInit {
3
+ auth?: ResolvedAuth;
4
+ token?: string;
5
+ refreshToken?: string;
6
+ origin?: string;
7
+ timeoutMs?: number;
8
+ onTokenRefreshed?: (newAuth: ResolvedAuth) => void;
9
+ fetchFn?: typeof fetch;
10
+ }
11
+ export interface AuthedFetchFactoryOptions {
12
+ token?: string;
13
+ refreshToken?: string;
14
+ origin?: string;
15
+ auth?: ResolvedAuth;
16
+ timeoutMs?: number;
17
+ onTokenRefreshed?: (newAuth: ResolvedAuth) => void;
18
+ fetchFn?: typeof fetch;
19
+ }
20
+ /**
21
+ * Creates a fetch-compatible closure pre-bound with authentication, automatic 401 refresh,
22
+ * and a default 30-second timeout per attempt.
23
+ */
24
+ export declare function createAuthedFetch(options: AuthedFetchFactoryOptions): typeof fetch;
25
+ /**
26
+ * Executes a fetch request with automatic OAuth token refresh on 401 Unauthorized.
27
+ * If token/auth has a refreshToken and the server responds with 401, attempts to refresh
28
+ * the token and retries the request once with the new token.
29
+ */
30
+ export declare function authenticatedFetch(input: string | URL | Request, options?: AuthenticatedFetchOptions): Promise<Response>;
31
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/client/http.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAElE,MAAM,WAAW,yBAA0B,SAAQ,WAAW;IAC5D,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,KAAK,CAYlF;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAC7B,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,QAAQ,CAAC,CA2DnB"}
@@ -0,0 +1,97 @@
1
+ /*
2
+ * Copyright (C) 2026 SPORT-SERVICE RS★R
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ import { refreshAccessToken } from './auth.js';
23
+ /**
24
+ * Creates a fetch-compatible closure pre-bound with authentication, automatic 401 refresh,
25
+ * and a default 30-second timeout per attempt.
26
+ */
27
+ export function createAuthedFetch(options) {
28
+ return (input, init) => authenticatedFetch(input, {
29
+ ...init,
30
+ auth: options.auth,
31
+ token: options.token,
32
+ refreshToken: options.refreshToken,
33
+ origin: options.origin,
34
+ timeoutMs: options.timeoutMs,
35
+ onTokenRefreshed: options.onTokenRefreshed,
36
+ fetchFn: options.fetchFn,
37
+ });
38
+ }
39
+ /**
40
+ * Executes a fetch request with automatic OAuth token refresh on 401 Unauthorized.
41
+ * If token/auth has a refreshToken and the server responds with 401, attempts to refresh
42
+ * the token and retries the request once with the new token.
43
+ */
44
+ export async function authenticatedFetch(input, options = {}) {
45
+ const fetchFn = options.fetchFn || fetch;
46
+ const { auth, token, refreshToken, origin, onTokenRefreshed, ...requestInit } = options;
47
+ const effectiveToken = auth?.token || token;
48
+ const effectiveRefreshToken = auth?.refreshToken || refreshToken;
49
+ const effectiveOrigin = auth?.origin || origin;
50
+ const timeoutMs = options.timeoutMs ?? 30_000;
51
+ let headers = new Headers(requestInit.headers);
52
+ if (effectiveToken && !headers.has('Authorization')) {
53
+ headers.set('Authorization', `Bearer ${effectiveToken}`);
54
+ }
55
+ // Create per-request abort signal with timeout if caller did not supply one
56
+ const getSignal = () => {
57
+ if (requestInit.signal)
58
+ return requestInit.signal;
59
+ if (timeoutMs > 0 && typeof AbortSignal !== 'undefined' && 'timeout' in AbortSignal) {
60
+ return AbortSignal.timeout(timeoutMs);
61
+ }
62
+ return undefined;
63
+ };
64
+ let response = await fetchFn(input, {
65
+ ...requestInit,
66
+ headers,
67
+ signal: getSignal(),
68
+ });
69
+ // If 401 and we have a refresh token, attempt automatic token recovery
70
+ if (response.status === 401 && effectiveRefreshToken && effectiveOrigin) {
71
+ try {
72
+ const authToRefresh = auth || {
73
+ source: 'emdash-cli',
74
+ token: effectiveToken || '',
75
+ refreshToken: effectiveRefreshToken,
76
+ origin: effectiveOrigin,
77
+ };
78
+ const refreshed = await refreshAccessToken(authToRefresh, undefined, fetchFn);
79
+ if (onTokenRefreshed) {
80
+ onTokenRefreshed(refreshed);
81
+ }
82
+ // Retry original request once with new token and a fresh timeout signal
83
+ const retryHeaders = new Headers(requestInit.headers);
84
+ retryHeaders.set('Authorization', `Bearer ${refreshed.token}`);
85
+ response = await fetchFn(input, {
86
+ ...requestInit,
87
+ headers: retryHeaders,
88
+ signal: getSignal(),
89
+ });
90
+ }
91
+ catch {
92
+ // If refresh fails, return original 401 response so caller can handle
93
+ }
94
+ }
95
+ return response;
96
+ }
97
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/client/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ export interface LockHolder {
2
+ userId: string;
3
+ userName: string;
4
+ acquiredAt: string;
5
+ expiresAt: string;
6
+ }
7
+ export interface LockResponse {
8
+ enabled: boolean;
9
+ holder: LockHolder | null;
10
+ heldByCaller: boolean;
11
+ }
12
+ export interface LockClientOptions {
13
+ origin: string;
14
+ token: string;
15
+ refreshToken?: string;
16
+ fetchFn?: typeof fetch;
17
+ }
18
+ export declare class EntryLockError extends Error {
19
+ code: string;
20
+ holder?: LockHolder | null;
21
+ constructor(message: string, code: string, holder?: LockHolder | null);
22
+ }
23
+ /**
24
+ * Checks lock status using GET /_emdash/api/content/{collection}/{id}/lock.
25
+ */
26
+ export declare function getLockStatus(collection: string, id: string, options: LockClientOptions): Promise<LockResponse>;
27
+ /**
28
+ * Acquires a 7-minute lease lock using POST /_emdash/api/content/{collection}/{id}/lock.
29
+ * Throws EntryLockError if another user holds the lock.
30
+ */
31
+ export declare function acquireLock(collection: string, id: string, options: LockClientOptions): Promise<LockResponse>;
32
+ /**
33
+ * Releases the lease lock using DELETE /_emdash/api/content/{collection}/{id}/lock.
34
+ */
35
+ export declare function releaseLock(collection: string, id: string, options: LockClientOptions): Promise<void>;
36
+ /**
37
+ * Executes a callback within a lock lease context, ensuring lock release via try/finally.
38
+ */
39
+ export declare function withEntryLock<T>(collection: string, id: string, options: LockClientOptions, action: () => Promise<T>): Promise<T>;
40
+ //# sourceMappingURL=lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/client/lock.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;CACvB;AAID,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,qBAAa,cAAe,SAAQ,KAAK;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAElC,YAAY,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,EAKpE;CACF;AAMD;;GAEG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,YAAY,CAAC,CAoBvB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,YAAY,CAAC,CAuBvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAOZ"}
@@ -0,0 +1,104 @@
1
+ /*
2
+ * Copyright (C) 2026 SPORT-SERVICE RS★R
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ import { createAuthedFetch } from './http.js';
23
+ export class EntryLockError extends Error {
24
+ code;
25
+ holder;
26
+ constructor(message, code, holder) {
27
+ super(message);
28
+ this.name = 'EntryLockError';
29
+ this.code = code;
30
+ this.holder = holder;
31
+ }
32
+ }
33
+ function createLockFetch(options) {
34
+ return createAuthedFetch(options);
35
+ }
36
+ /**
37
+ * Checks lock status using GET /_emdash/api/content/{collection}/{id}/lock.
38
+ */
39
+ export async function getLockStatus(collection, id, options) {
40
+ const fetchFn = createLockFetch(options);
41
+ const url = new URL(`/_emdash/api/content/${collection}/${id}/lock`, options.origin).toString();
42
+ const res = await fetchFn(url, {
43
+ method: 'GET',
44
+ headers: {
45
+ Authorization: `Bearer ${options.token}`,
46
+ Accept: 'application/json',
47
+ },
48
+ });
49
+ if (!res.ok) {
50
+ throw new EntryLockError(`Failed to get lock status for ${collection}/${id}: ${res.statusText}`, 'LOCK_STATUS_ERROR');
51
+ }
52
+ return (await res.json());
53
+ }
54
+ /**
55
+ * Acquires a 7-minute lease lock using POST /_emdash/api/content/{collection}/{id}/lock.
56
+ * Throws EntryLockError if another user holds the lock.
57
+ */
58
+ export async function acquireLock(collection, id, options) {
59
+ const fetchFn = createLockFetch(options);
60
+ const url = new URL(`/_emdash/api/content/${collection}/${id}/lock`, options.origin).toString();
61
+ const res = await fetchFn(url, {
62
+ method: 'POST',
63
+ headers: {
64
+ Authorization: `Bearer ${options.token}`,
65
+ Accept: 'application/json',
66
+ },
67
+ });
68
+ const json = (await res.json());
69
+ if (json.holder && !json.heldByCaller) {
70
+ throw new EntryLockError(`Entry '${id}' is currently locked by ${json.holder.userName} (expires at ${json.holder.expiresAt}).`, 'ENTRY_LOCKED', json.holder);
71
+ }
72
+ return json;
73
+ }
74
+ /**
75
+ * Releases the lease lock using DELETE /_emdash/api/content/{collection}/{id}/lock.
76
+ */
77
+ export async function releaseLock(collection, id, options) {
78
+ const fetchFn = createLockFetch(options);
79
+ const url = new URL(`/_emdash/api/content/${collection}/${id}/lock`, options.origin).toString();
80
+ try {
81
+ await fetchFn(url, {
82
+ method: 'DELETE',
83
+ headers: {
84
+ Authorization: `Bearer ${options.token}`,
85
+ },
86
+ });
87
+ }
88
+ catch {
89
+ // Best-effort release; do not crash caller if network fails on release
90
+ }
91
+ }
92
+ /**
93
+ * Executes a callback within a lock lease context, ensuring lock release via try/finally.
94
+ */
95
+ export async function withEntryLock(collection, id, options, action) {
96
+ await acquireLock(collection, id, options);
97
+ try {
98
+ return await action();
99
+ }
100
+ finally {
101
+ await releaseLock(collection, id, options);
102
+ }
103
+ }
104
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/client/lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAeH,OAAO,EAAsB,iBAAiB,EAAE,MAAM,WAAW,CAAC;AASlE,MAAM,OAAO,cAAe,SAAQ,KAAK;IAChC,IAAI,CAAS;IACb,MAAM,CAAqB;IAElC,YAAY,OAAe,EAAE,IAAY,EAAE,MAA0B;QACnE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,SAAS,eAAe,CAAC,OAA0B;IACjD,OAAO,iBAAiB,CAAC,OAAO,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,UAAkB,EAClB,EAAU,EACV,OAA0B;IAE1B,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,wBAAwB,UAAU,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEhG,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE;QAC7B,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE;YACxC,MAAM,EAAE,kBAAkB;SAC3B;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,cAAc,CACtB,iCAAiC,UAAU,IAAI,EAAE,KAAK,GAAG,CAAC,UAAU,EAAE,EACtE,mBAAmB,CACpB,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAiB,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,UAAkB,EAClB,EAAU,EACV,OAA0B;IAE1B,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,wBAAwB,UAAU,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEhG,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE;QAC7B,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE;YACxC,MAAM,EAAE,kBAAkB;SAC3B;KACF,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAiB,CAAC;IAEhD,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACtC,MAAM,IAAI,cAAc,CACtB,UAAU,EAAE,4BAA4B,IAAI,CAAC,MAAM,CAAC,QAAQ,gBAAgB,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,EACrG,cAAc,EACd,IAAI,CAAC,MAAM,CACZ,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,UAAkB,EAClB,EAAU,EACV,OAA0B;IAE1B,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,wBAAwB,UAAU,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEhG,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,GAAG,EAAE;YACjB,MAAM,EAAE,QAAQ;YAChB,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE;aACzC;SACF,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;IACzE,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,UAAkB,EAClB,EAAU,EACV,OAA0B,EAC1B,MAAwB;IAExB,MAAM,WAAW,CAAC,UAAU,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,OAAO,MAAM,MAAM,EAAE,CAAC;IACxB,CAAC;YAAS,CAAC;QACT,MAAM,WAAW,CAAC,UAAU,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { Frontmatter, ParsedMarkdown } from '../utils/frontmatter.js';
2
+ export interface ContentBylineInput {
3
+ bylineId: string;
4
+ roleLabel?: string | null;
5
+ }
6
+ export interface ContentUpdatePayload {
7
+ id?: string;
8
+ collection: string;
9
+ slug?: string;
10
+ status?: 'draft' | 'published';
11
+ publishedAt?: string | null;
12
+ locale?: string;
13
+ data: Record<string, unknown>;
14
+ taxonomies?: Record<string, string[]>;
15
+ seo?: Record<string, unknown>;
16
+ bylines?: ContentBylineInput[];
17
+ _rev?: string;
18
+ overrideLock?: boolean;
19
+ }
20
+ export interface MapperOptions {
21
+ allowPublish?: boolean;
22
+ bylineSlugToId?: Record<string, string>;
23
+ bylineIdToSlug?: Record<string, string>;
24
+ }
25
+ /**
26
+ * Converts local markdown representation into EmDash REST API update payload.
27
+ */
28
+ export declare function localToApiPayload(parsed: ParsedMarkdown, rev: string, options?: MapperOptions): ContentUpdatePayload;
29
+ /**
30
+ * Converts remote EmDash content API response item into local frontmatter & markdown body.
31
+ */
32
+ export declare function apiResponseToLocal(raw: Record<string, unknown>, options?: MapperOptions): {
33
+ frontmatter: Frontmatter;
34
+ body: string;
35
+ rev: string;
36
+ };
37
+ //# sourceMappingURL=mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../../src/client/mapper.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE3E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,aAAa,GACtB,oBAAoB,CA+CtB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,OAAO,CAAC,EAAE,aAAa,GACtB;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAuEzD"}
@@ -0,0 +1,134 @@
1
+ /*
2
+ * Copyright (C) 2026 SPORT-SERVICE RS★R
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ import { markdownToPortableText, portableTextToMarkdown, } from './portable-text.js';
23
+ import { unwrapItem, extractRev } from './api.js';
24
+ /**
25
+ * Converts local markdown representation into EmDash REST API update payload.
26
+ */
27
+ export function localToApiPayload(parsed, rev, options) {
28
+ const { frontmatter, body } = parsed;
29
+ const ptBody = markdownToPortableText(body);
30
+ const payload = {
31
+ id: frontmatter.id,
32
+ collection: frontmatter.collection,
33
+ slug: frontmatter.slug,
34
+ locale: frontmatter.locale,
35
+ data: {
36
+ title: frontmatter.title,
37
+ content: ptBody,
38
+ },
39
+ _rev: rev,
40
+ };
41
+ // Staging Protection (G3): Only include status: 'published' if allowPublish is true
42
+ if (frontmatter.status === 'published' && options?.allowPublish) {
43
+ payload.status = 'published';
44
+ }
45
+ else if (frontmatter.status === 'draft') {
46
+ // If explicitly set to draft, we can send draft or omit
47
+ // (Omission maintains draft/staging mode on remote)
48
+ }
49
+ if (frontmatter.publishedAt !== undefined) {
50
+ payload.publishedAt = frontmatter.publishedAt;
51
+ }
52
+ if (frontmatter.seo) {
53
+ payload.seo = {
54
+ title: frontmatter.seo.title ?? null,
55
+ description: frontmatter.seo.description ?? null,
56
+ canonical: frontmatter.seo.canonical ?? null,
57
+ noIndex: frontmatter.seo.noIndex ?? false,
58
+ image: frontmatter.seo.image ?? null,
59
+ };
60
+ }
61
+ if (frontmatter.bylines && frontmatter.bylines.length > 0) {
62
+ const slugMap = options?.bylineSlugToId || {};
63
+ payload.bylines = frontmatter.bylines.map((slug) => ({
64
+ bylineId: slugMap[slug] || slug,
65
+ roleLabel: null,
66
+ }));
67
+ }
68
+ return payload;
69
+ }
70
+ /**
71
+ * Converts remote EmDash content API response item into local frontmatter & markdown body.
72
+ */
73
+ export function apiResponseToLocal(raw, options) {
74
+ const item = unwrapItem(raw);
75
+ const rev = extractRev(raw);
76
+ const id = String(item.id || '');
77
+ const slug = String(item.slug || '');
78
+ const collection = String(item.collection || item.type || 'posts');
79
+ const status = (item.status === 'published' ? 'published' : 'draft');
80
+ const locale = String(item.locale || 'ja');
81
+ const publishedAt = item.publishedAt ? String(item.publishedAt) : null;
82
+ const data = (item.data || {});
83
+ const title = String(data.title || item.title || 'Untitled');
84
+ const rawBody = data.content ?? data.body;
85
+ let body = '';
86
+ if (Array.isArray(rawBody)) {
87
+ body = portableTextToMarkdown(rawBody);
88
+ }
89
+ else if (typeof rawBody === 'string') {
90
+ body = rawBody;
91
+ }
92
+ // Taxonomies
93
+ const taxonomies = (item.taxonomies || {});
94
+ // SEO
95
+ const rawSeo = (item.seo || {});
96
+ const seo = Object.keys(rawSeo).length > 0
97
+ ? {
98
+ title: rawSeo.title ? String(rawSeo.title) : null,
99
+ description: rawSeo.description ? String(rawSeo.description) : null,
100
+ canonical: rawSeo.canonical ? String(rawSeo.canonical) : null,
101
+ noIndex: Boolean(rawSeo.noIndex),
102
+ image: rawSeo.image ? String(rawSeo.image) : null,
103
+ }
104
+ : undefined;
105
+ // Bylines (support nested byline.slug, byline.id, or bylineId)
106
+ const idMap = options?.bylineIdToSlug || {};
107
+ const rawBylines = (item.bylines || []);
108
+ let bylines = rawBylines
109
+ .map((b) => {
110
+ const slugOrId = b.byline?.slug || b.bylineId || b.byline?.id;
111
+ return slugOrId ? idMap[slugOrId] || slugOrId : null;
112
+ })
113
+ .filter((b) => Boolean(b));
114
+ if (bylines.length === 0 && item.byline && typeof item.byline === 'object') {
115
+ const singleByline = item.byline;
116
+ const slugOrId = singleByline.slug || singleByline.id;
117
+ if (slugOrId)
118
+ bylines = [idMap[slugOrId] || slugOrId];
119
+ }
120
+ const frontmatter = {
121
+ id,
122
+ slug,
123
+ title,
124
+ collection,
125
+ status,
126
+ publishedAt,
127
+ locale,
128
+ taxonomies,
129
+ seo,
130
+ bylines,
131
+ };
132
+ return { frontmatter, body, rev };
133
+ }
134
+ //# sourceMappingURL=mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.js","sourceRoot":"","sources":["../../src/client/mapper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * EmDash Portable Text <-> Markdown conversion layer.
3
+ * Ported from EmDash (packages/core/src/client/portable-text.ts)
4
+ * Licensed under the MIT License. Copyright (c) EmDash authors.
5
+ *
6
+ * Three tiers of block handling:
7
+ * Tier 1: Standard PT blocks <-> standard Markdown (headings, paragraphs, lists, etc.)
8
+ * Tier 2: EmDash custom blocks <-> Markdown directives (future)
9
+ * Tier 3: Unknown blocks <-> opaque HTML comment fences (preserved, not editable)
10
+ */
11
+ /** Minimal Portable Text block shape */
12
+ export interface PortableTextBlock {
13
+ _type: string;
14
+ _key?: string;
15
+ style?: string;
16
+ level?: number;
17
+ listItem?: string;
18
+ markDefs?: MarkDef[];
19
+ children?: PortableTextSpan[];
20
+ [key: string]: unknown;
21
+ }
22
+ interface PortableTextSpan {
23
+ _type: string;
24
+ _key?: string;
25
+ text?: string;
26
+ marks?: string[];
27
+ [key: string]: unknown;
28
+ }
29
+ interface MarkDef {
30
+ _key: string;
31
+ _type: string;
32
+ href?: string;
33
+ [key: string]: unknown;
34
+ }
35
+ /**
36
+ * Convert Portable Text blocks to Markdown.
37
+ * Unknown block types are serialized as opaque fences.
38
+ */
39
+ export declare function portableTextToMarkdown(blocks: PortableTextBlock[]): string;
40
+ /**
41
+ * Convert Markdown to Portable Text blocks.
42
+ * Opaque fences (<!--ec:block ... -->) are deserialized and spliced back in.
43
+ */
44
+ export declare function markdownToPortableText(markdown: string): PortableTextBlock[];
45
+ /** Reset key counter (useful for testing) */
46
+ export declare function resetKeyCounter(): void;
47
+ export interface FieldSchema {
48
+ slug: string;
49
+ type: string;
50
+ validation?: unknown;
51
+ blockTypes?: Array<{
52
+ slug: string;
53
+ currentVersion: number;
54
+ versions: Array<{
55
+ version: number;
56
+ fields: Array<{
57
+ slug: string;
58
+ type: string;
59
+ }>;
60
+ }>;
61
+ }>;
62
+ }
63
+ /**
64
+ * Convert content data for reading: Portable Text arrays -> Markdown strings.
65
+ * Converts top-level `portableText` arrays and nested `portableText` arrays
66
+ * inside `blocks` arrays.
67
+ */
68
+ export declare function convertDataForRead(data: Record<string, unknown>, fields: FieldSchema[], raw?: boolean): Record<string, unknown>;
69
+ /**
70
+ * Convert content data for writing: Markdown strings -> Portable Text arrays.
71
+ * Converts top-level `portableText` strings and nested Markdown strings
72
+ * in `portableText` fields inside `blocks` arrays.
73
+ */
74
+ export declare function convertDataForWrite(data: Record<string, unknown>, fields: FieldSchema[]): Record<string, unknown>;
75
+ /**
76
+ * Strips code fences (```...```) from markdown to prevent false positives in regex checks.
77
+ */
78
+ export declare function stripCodeBlocks(markdown: string): string;
79
+ /**
80
+ * Detects syntax that is unsupported by the line-based EmDash parser,
81
+ * such as markdown tables, raw block HTML, or mixed inline images.
82
+ */
83
+ export declare function detectUnsupportedMarkdownSyntax(markdown: string): string[];
84
+ /**
85
+ * Extracts all opaque fence lines (`<!--ec:block ... -->`) from markdown.
86
+ */
87
+ export declare function extractOpaqueBlockLines(markdown: string): string[];
88
+ /**
89
+ * Verifies that all opaque block fences present in baseMarkdown are intact in localMarkdown (G9 guard).
90
+ * Returns true if untampered, false if any base opaque block fence was modified or removed.
91
+ */
92
+ export declare function verifyOpaqueBlocksUntampered(baseMarkdown: string, localMarkdown: string): boolean;
93
+ export {};
94
+ //# sourceMappingURL=portable-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portable-text.d.ts","sourceRoot":"","sources":["../../src/client/portable-text.ts"],"names":[],"mappings":"AAsBA;;;;;;;;;GASG;AAMH,wCAAwC;AACxC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,OAAO;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAWD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAwC1E;AAiFD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAiG5E;AAwFD,6CAA6C;AAC7C,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAMD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,EAAE,KAAK,CAAC;YACd,OAAO,EAAE,MAAM,CAAC;YAChB,MAAM,EAAE,KAAK,CAAC;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,CAAC,CAAC;SAC/C,CAAC,CAAC;KACJ,CAAC,CAAC;CACJ;AA0CD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,WAAW,EAAE,EACrB,GAAG,GAAE,OAAe,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYzB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,WAAW,EAAE,GACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB;AAMD;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAmB1E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAGlE;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAQjG"}