@relayfile/adapter-confluence 0.1.0 → 0.1.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 (61) hide show
  1. package/discovery/confluence/.adapter.md +4 -4
  2. package/dist/__tests__/alias-slug.test.d.ts +2 -0
  3. package/dist/__tests__/alias-slug.test.d.ts.map +1 -0
  4. package/dist/__tests__/alias-slug.test.js +19 -0
  5. package/dist/__tests__/alias-slug.test.js.map +1 -0
  6. package/dist/__tests__/confluence-adapter.test.js +8 -8
  7. package/dist/__tests__/index-emission.test.d.ts +2 -0
  8. package/dist/__tests__/index-emission.test.d.ts.map +1 -0
  9. package/dist/__tests__/index-emission.test.js +67 -0
  10. package/dist/__tests__/index-emission.test.js.map +1 -0
  11. package/dist/__tests__/layout-prompt.test.d.ts +2 -0
  12. package/dist/__tests__/layout-prompt.test.d.ts.map +1 -0
  13. package/dist/__tests__/layout-prompt.test.js +18 -0
  14. package/dist/__tests__/layout-prompt.test.js.map +1 -0
  15. package/dist/__tests__/path-mapper.test.d.ts +2 -0
  16. package/dist/__tests__/path-mapper.test.d.ts.map +1 -0
  17. package/dist/__tests__/path-mapper.test.js +90 -0
  18. package/dist/__tests__/path-mapper.test.js.map +1 -0
  19. package/dist/__tests__/webhook-normalizer.test.d.ts +2 -0
  20. package/dist/__tests__/webhook-normalizer.test.d.ts.map +1 -0
  21. package/dist/__tests__/webhook-normalizer.test.js +106 -0
  22. package/dist/__tests__/webhook-normalizer.test.js.map +1 -0
  23. package/dist/alias-slug.d.ts +9 -0
  24. package/dist/alias-slug.d.ts.map +1 -0
  25. package/dist/alias-slug.js +23 -0
  26. package/dist/alias-slug.js.map +1 -0
  27. package/dist/index-emitter.d.ts +10 -0
  28. package/dist/index-emitter.d.ts.map +1 -0
  29. package/dist/index-emitter.js +26 -0
  30. package/dist/index-emitter.js.map +1 -0
  31. package/dist/index.d.ts +12 -3
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +8 -3
  34. package/dist/index.js.map +1 -1
  35. package/dist/layout-prompt.d.ts +7 -0
  36. package/dist/layout-prompt.d.ts.map +1 -0
  37. package/dist/layout-prompt.js +56 -0
  38. package/dist/layout-prompt.js.map +1 -0
  39. package/dist/path-mapper.d.ts +40 -2
  40. package/dist/path-mapper.d.ts.map +1 -1
  41. package/dist/path-mapper.js +155 -10
  42. package/dist/path-mapper.js.map +1 -1
  43. package/dist/queries.d.ts +22 -2
  44. package/dist/queries.d.ts.map +1 -1
  45. package/dist/queries.js +43 -2
  46. package/dist/queries.js.map +1 -1
  47. package/dist/resources.js +2 -2
  48. package/dist/resources.js.map +1 -1
  49. package/dist/types.d.ts +1 -0
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/types.js +1 -0
  52. package/dist/types.js.map +1 -1
  53. package/dist/webhook-normalizer.d.ts +59 -0
  54. package/dist/webhook-normalizer.d.ts.map +1 -0
  55. package/dist/webhook-normalizer.js +469 -0
  56. package/dist/webhook-normalizer.js.map +1 -0
  57. package/dist/writeback.d.ts +1 -2
  58. package/dist/writeback.d.ts.map +1 -1
  59. package/dist/writeback.js +1 -1
  60. package/dist/writeback.js.map +1 -1
  61. package/package.json +22 -2
@@ -11,8 +11,8 @@ Resources:
11
11
 
12
12
  | Resource | Schema | Create example | ID pattern | What it does |
13
13
  |---|---|---|---|---|
14
- | `/confluence/pages/<id>.json` | `/confluence/pages/.schema.json` | `/confluence/pages/.create.example.json` | `^(?:[A-Za-z0-9_.~-]+--)?\d+$` | Creates a Confluence page when `spaceId` is supplied in the document. |
15
- | `/confluence/spaces/{spaceIdOrKey}/pages/<id>.json` | `/confluence/spaces/{spaceIdOrKey}/pages/.schema.json` | `/confluence/spaces/{spaceIdOrKey}/pages/.create.example.json` | `^(?:[A-Za-z0-9_.~-]+--)?\d+$` | Creates a Confluence page in the space named by the path. |
14
+ | `/confluence/pages/<id>.json` | `/confluence/pages/.schema.json` | `/confluence/pages/.create.example.json` | `^(?:[A-Za-z0-9_.~-]+(?:--\|__))?\d+$` | Creates a Confluence page when `spaceId` is supplied in the document. |
15
+ | `/confluence/spaces/{spaceIdOrKey}/pages/<id>.json` | `/confluence/spaces/{spaceIdOrKey}/pages/.schema.json` | `/confluence/spaces/{spaceIdOrKey}/pages/.create.example.json` | `^(?:[A-Za-z0-9_.~-]+(?:--\|__))?\d+$` | Creates a Confluence page in the space named by the path. |
16
16
 
17
17
  ## Operations
18
18
 
@@ -24,8 +24,8 @@ Resources:
24
24
  | Delete | `rm <id>.json` for canonical ids. |
25
25
 
26
26
  ## ID Patterns
27
- - `/confluence/pages/<id>.json`: `^(?:[A-Za-z0-9_.~-]+--)?\d+$`. Filenames that do not match this pattern are treated as create drafts.
28
- - `/confluence/spaces/{spaceIdOrKey}/pages/<id>.json`: `^(?:[A-Za-z0-9_.~-]+--)?\d+$`. Filenames that do not match this pattern are treated as create drafts.
27
+ - `/confluence/pages/<id>.json`: `^(?:[A-Za-z0-9_.~-]+(?:--\|__))?\d+$`. Filenames that do not match this pattern are treated as create drafts.
28
+ - `/confluence/spaces/{spaceIdOrKey}/pages/<id>.json`: `^(?:[A-Za-z0-9_.~-]+(?:--\|__))?\d+$`. Filenames that do not match this pattern are treated as create drafts.
29
29
 
30
30
  ## Write field contracts
31
31
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=alias-slug.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alias-slug.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/alias-slug.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,19 @@
1
+ import assert from 'node:assert/strict';
2
+ import { describe, it } from 'node:test';
3
+ import { aliasCollisionSuffix, slugifyAlias } from '../alias-slug.js';
4
+ describe('confluence alias slug', () => {
5
+ it('slugging is deterministic, ASCII-folded, and strips traversal characters', () => {
6
+ assert.equal(slugifyAlias('Café ../ Roadmap'), 'cafe-roadmap');
7
+ assert.equal(slugifyAlias('Café ../ Roadmap'), slugifyAlias('Café ../ Roadmap'));
8
+ });
9
+ it('falls back to "untitled" when the input slugs to nothing', () => {
10
+ assert.equal(slugifyAlias('🚀🔥'), 'untitled');
11
+ assert.equal(slugifyAlias(' '), 'untitled');
12
+ });
13
+ it('emits an 8-char hex collision suffix from the id', () => {
14
+ const suffix = aliasCollisionSuffix('page-id-1');
15
+ assert.match(suffix, /^[0-9a-f]{8}$/u);
16
+ assert.equal(suffix, aliasCollisionSuffix('page-id-1'));
17
+ });
18
+ });
19
+ //# sourceMappingURL=alias-slug.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alias-slug.test.js","sourceRoot":"","sources":["../../src/__tests__/alias-slug.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEtE,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,CAAC,EAAE,cAAc,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,CAAC,EAAE,YAAY,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,MAAM,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -31,13 +31,13 @@ function createAdapter(client = createClient()) {
31
31
  }
32
32
  describe('ConfluenceAdapter', () => {
33
33
  it('computes deterministic Confluence paths', () => {
34
- assert.equal(computeConfluencePath('space', '12345', { title: 'Engineering Docs' }), '/confluence/spaces/engineering-docs--12345.json');
35
- assert.equal(computeConfluencePath('page', '98765', { title: 'Release Plan', spaceId: '12345' }), '/confluence/spaces/12345/pages/release-plan--98765.json');
34
+ assert.equal(computeConfluencePath('space', '12345', { title: 'Engineering Docs' }), '/confluence/spaces/engineering-docs__12345.json');
35
+ assert.equal(computeConfluencePath('page', '98765', { title: 'Release Plan', spaceId: '12345' }), '/confluence/spaces/12345/pages/release-plan__98765.json');
36
36
  });
37
37
  it('materializes spaces and pages from Nango-style sync records', () => {
38
38
  const adapter = createAdapter();
39
39
  assert.deepEqual(adapter.materializeSpace({ id: '12345', key: 'ENG', name: 'Engineering' }), {
40
- path: '/confluence/spaces/engineering--12345.json',
40
+ path: '/confluence/spaces/engineering__12345.json',
41
41
  payload: {
42
42
  provider: 'confluence',
43
43
  objectType: 'space',
@@ -45,7 +45,7 @@ describe('ConfluenceAdapter', () => {
45
45
  payload: { id: '12345', key: 'ENG', name: 'Engineering' },
46
46
  },
47
47
  });
48
- assert.equal(adapter.materializePage({ id: '98765', title: 'Release Plan', spaceId: '12345' }).path, '/confluence/spaces/12345/pages/release-plan--98765.json');
48
+ assert.equal(adapter.materializePage({ id: '98765', title: 'Release Plan', spaceId: '12345' }).path, '/confluence/spaces/12345/pages/release-plan__98765.json');
49
49
  });
50
50
  it('ingests page events with space relations and body comments', async () => {
51
51
  const client = createClient();
@@ -64,7 +64,7 @@ describe('ConfluenceAdapter', () => {
64
64
  },
65
65
  });
66
66
  assert.equal(result.filesWritten, 1);
67
- assert.equal(client.writes[0]?.path, '/confluence/spaces/12345/pages/release-plan--98765.json');
67
+ assert.equal(client.writes[0]?.path, '/confluence/spaces/12345/pages/release-plan__98765.json');
68
68
  assert.deepEqual(client.writes[0]?.semantics?.relations, [
69
69
  confluenceSpacePath('12345'),
70
70
  ]);
@@ -83,7 +83,7 @@ describe('ConfluenceAdapter', () => {
83
83
  endpoint: '/wiki/api/v2/pages',
84
84
  query: { limit: '100', 'body-format': 'storage', 'space-id': '12345' },
85
85
  });
86
- assert.deepEqual(resolveConfluenceReadRequest('/confluence/pages/release-plan--98765.json'), {
86
+ assert.deepEqual(resolveConfluenceReadRequest('/confluence/pages/release-plan__98765.json'), {
87
87
  action: 'get_page',
88
88
  method: 'GET',
89
89
  endpoint: '/wiki/api/v2/pages/98765',
@@ -107,7 +107,7 @@ describe('ConfluenceAdapter', () => {
107
107
  });
108
108
  });
109
109
  it('resolves page updates and increments synced version numbers', () => {
110
- assert.deepEqual(resolveConfluenceWritebackRequest('/confluence/pages/release-plan--98765.json', JSON.stringify({
110
+ assert.deepEqual(resolveConfluenceWritebackRequest('/confluence/pages/release-plan__98765.json', JSON.stringify({
111
111
  provider: 'confluence',
112
112
  objectType: 'page',
113
113
  objectId: '98765',
@@ -134,7 +134,7 @@ describe('ConfluenceAdapter', () => {
134
134
  });
135
135
  });
136
136
  it('resolves page deletes and rejects read-only fields', () => {
137
- assert.deepEqual(resolveConfluenceDeleteRequest('/confluence/pages/release-plan--98765.json'), {
137
+ assert.deepEqual(resolveConfluenceDeleteRequest('/confluence/pages/release-plan__98765.json'), {
138
138
  action: 'delete_page',
139
139
  method: 'DELETE',
140
140
  endpoint: '/wiki/api/v2/pages/98765',
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index-emission.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-emission.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/index-emission.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,67 @@
1
+ import assert from 'node:assert/strict';
2
+ import { describe, it } from 'node:test';
3
+ import { buildConfluenceIndexFile } from '../index-emitter.js';
4
+ import { confluencePagePath, confluenceSpacePath, } from '../path-mapper.js';
5
+ import { confluencePageIndexRow, confluenceSpaceIndexRow } from '../queries.js';
6
+ describe('confluence index emission', () => {
7
+ it('emits deterministic page and space indexes sorted by updated DESC, then id ASC', () => {
8
+ const pageRows = [
9
+ confluencePageIndexRow({
10
+ id: '98765',
11
+ title: 'Release Plan',
12
+ spaceId: '12345',
13
+ status: 'current',
14
+ createdAt: '2026-04-01T08:00:00.000Z',
15
+ }),
16
+ confluencePageIndexRow({
17
+ id: '99999',
18
+ title: 'Draft notes',
19
+ spaceId: '12345',
20
+ status: 'draft',
21
+ createdAt: '2026-04-03T10:00:00.000Z',
22
+ }),
23
+ ];
24
+ const spaceRows = [
25
+ confluenceSpaceIndexRow({
26
+ id: '12345',
27
+ key: 'ENG',
28
+ name: 'Engineering',
29
+ createdAt: '2026-04-01T08:00:00.000Z',
30
+ }),
31
+ confluenceSpaceIndexRow({
32
+ id: '67890',
33
+ key: 'OPS',
34
+ name: 'Operations',
35
+ createdAt: '2026-04-03T10:00:00.000Z',
36
+ }),
37
+ ];
38
+ const pageIndex = buildConfluenceIndexFile('pages', pageRows);
39
+ const pageIndexAgain = buildConfluenceIndexFile('pages', [...pageRows].reverse());
40
+ const spaceIndex = buildConfluenceIndexFile('spaces', spaceRows);
41
+ assert.deepEqual(pageIndex, pageIndexAgain);
42
+ assert.equal(pageIndex.path, '/confluence/pages/_index.json');
43
+ assert.equal(spaceIndex.path, '/confluence/spaces/_index.json');
44
+ assert.equal(pageIndex.contentType, 'application/json; charset=utf-8');
45
+ assert.deepEqual(JSON.parse(pageIndex.content), [
46
+ { id: '99999', title: 'Draft notes', updated: '2026-04-03T10:00:00.000Z', spaceId: '12345', status: 'draft' },
47
+ { id: '98765', title: 'Release Plan', updated: '2026-04-01T08:00:00.000Z', spaceId: '12345', status: 'current' },
48
+ ]);
49
+ assert.deepEqual(JSON.parse(spaceIndex.content), [
50
+ { id: '67890', title: 'Operations', updated: '2026-04-03T10:00:00.000Z', key: 'OPS' },
51
+ { id: '12345', title: 'Engineering', updated: '2026-04-01T08:00:00.000Z', key: 'ENG' },
52
+ ]);
53
+ assert.equal(confluencePagePath('98765'), '/confluence/pages/98765.json');
54
+ assert.equal(confluenceSpacePath('12345'), '/confluence/spaces/12345.json');
55
+ });
56
+ it('emits an empty index when a Confluence bucket has no records', () => {
57
+ const file = buildConfluenceIndexFile('pages', []);
58
+ assert.equal(file.path, '/confluence/pages/_index.json');
59
+ assert.deepEqual(JSON.parse(file.content), []);
60
+ });
61
+ it('re-exports the index and layout helpers from the barrel', async () => {
62
+ const barrel = await import('../index.js');
63
+ assert.equal(barrel.buildConfluenceIndexFile, buildConfluenceIndexFile);
64
+ assert.equal(typeof barrel.confluenceLayoutPromptFile, 'function');
65
+ });
66
+ });
67
+ //# sourceMappingURL=index-emission.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-emission.test.js","sourceRoot":"","sources":["../../src/__tests__/index-emission.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=layout-prompt.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-prompt.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/layout-prompt.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import assert from 'node:assert/strict';
2
+ import { describe, it } from 'node:test';
3
+ import { confluenceLayoutPromptFile } from '../layout-prompt.js';
4
+ describe('confluence layout prompt', () => {
5
+ it('emits the integration layout guide at the confluence root', () => {
6
+ const file = confluenceLayoutPromptFile();
7
+ assert.equal(file.path, '/confluence/LAYOUT.md');
8
+ assert.equal(file.contentType, 'text/markdown; charset=utf-8');
9
+ assert.match(file.content, /\bls\b/u);
10
+ assert.match(file.content, /__/u);
11
+ assert.match(file.content, /_index\.json/u);
12
+ assert.match(file.content, /\/confluence\/pages\//u);
13
+ assert.match(file.content, /\/confluence\/spaces\//u);
14
+ assert.match(file.content, /by-title/u);
15
+ assert.match(file.content, /by-id/u);
16
+ });
17
+ });
18
+ //# sourceMappingURL=layout-prompt.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-prompt.test.js","sourceRoot":"","sources":["../../src/__tests__/layout-prompt.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAEjE,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,IAAI,GAAG,0BAA0B,EAAE,CAAC;QAE1C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,uBAAuB,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,8BAA8B,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC;QACrD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;QACtD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=path-mapper.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-mapper.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/path-mapper.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,90 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { computeConfluencePath, confluenceByIdAliasPath, confluenceByTitleAliasPath, confluencePageByIdAliasPath, confluencePageByStatePath, confluencePageByTitleAliasPath, confluencePagePath, confluencePagesIndexPath, confluenceProviderRootIndexPath, confluenceSpaceByIdAliasPath, confluenceSpacePath, confluenceSpacesIndexPath, extractConfluenceIdFromPathSegment, nameWithId, normalizeConfluenceObjectType, normalizeNangoConfluenceModel, parseNameWithId, slugifyStatusName, tryNormalizeConfluenceObjectType, } from '../path-mapper.js';
4
+ describe('confluence path-mapper', () => {
5
+ describe('normalizeConfluenceObjectType', () => {
6
+ it('accepts canonical and plural variants', () => {
7
+ assert.equal(normalizeConfluenceObjectType('page'), 'page');
8
+ assert.equal(normalizeConfluenceObjectType('PAGES'), 'page');
9
+ assert.equal(normalizeConfluenceObjectType('Space'), 'space');
10
+ assert.equal(normalizeConfluenceObjectType('spaces'), 'space');
11
+ });
12
+ it('accepts Nango-style PascalCase model names', () => {
13
+ assert.equal(normalizeNangoConfluenceModel('ConfluencePage'), 'page');
14
+ assert.equal(normalizeNangoConfluenceModel('ConfluenceSpace'), 'space');
15
+ });
16
+ it('throws on unknown types', () => {
17
+ assert.throws(() => normalizeConfluenceObjectType('flarb'));
18
+ assert.equal(tryNormalizeConfluenceObjectType('flarb'), undefined);
19
+ });
20
+ });
21
+ describe('nameWithId', () => {
22
+ it('produces <slug>__<id> for page and space leaves', () => {
23
+ assert.equal(confluencePagePath('98765', 'Release Plan'), '/confluence/pages/release-plan__98765.json');
24
+ assert.equal(confluenceSpacePath('12345', 'Engineering Docs'), '/confluence/spaces/engineering-docs__12345.json');
25
+ });
26
+ it('falls back to <id>.json when the title is missing or slugs to nothing', () => {
27
+ assert.equal(confluencePagePath('98765'), '/confluence/pages/98765.json');
28
+ assert.equal(confluencePagePath('98765', ' '), '/confluence/pages/98765.json');
29
+ assert.equal(confluencePagePath('98765', '{{}}'), '/confluence/pages/98765.json');
30
+ });
31
+ it('emits a space-scoped page path under spaces/<spaceId>/pages', () => {
32
+ assert.equal(computeConfluencePath('page', '98765', { title: 'Release Plan', spaceId: '12345' }), '/confluence/spaces/12345/pages/release-plan__98765.json');
33
+ });
34
+ it('disambiguates collisions with an 8-char hash suffix', () => {
35
+ const seen = new Set();
36
+ const first = nameWithId('Roadmap', 'page-1', { existingNames: seen });
37
+ const second = nameWithId('Roadmap', 'page-2', { existingNames: seen });
38
+ assert.equal(first, 'roadmap__page-1');
39
+ assert.match(second, /^roadmap-[0-9a-f]{8}__page-2$/u);
40
+ });
41
+ });
42
+ describe('parseNameWithId', () => {
43
+ it('splits <slug>__<id>.json leaves', () => {
44
+ assert.deepEqual(parseNameWithId('release-plan__98765.json'), {
45
+ humanReadable: 'release-plan',
46
+ id: '98765',
47
+ ext: 'json',
48
+ });
49
+ });
50
+ it('returns a bare id when the leaf has no slug prefix', () => {
51
+ assert.deepEqual(parseNameWithId('98765.json'), {
52
+ humanReadable: null,
53
+ id: '98765',
54
+ ext: 'json',
55
+ });
56
+ });
57
+ });
58
+ describe('index paths', () => {
59
+ it('returns canonical bucket and root index paths', () => {
60
+ assert.equal(confluencePagesIndexPath(), '/confluence/pages/_index.json');
61
+ assert.equal(confluenceSpacesIndexPath(), '/confluence/spaces/_index.json');
62
+ assert.equal(confluenceProviderRootIndexPath(), '/confluence/_index.json');
63
+ });
64
+ });
65
+ describe('alias paths', () => {
66
+ it('produces by-id and by-title alias paths for pages and spaces', () => {
67
+ assert.equal(confluencePageByIdAliasPath('98765'), '/confluence/pages/by-id/98765.json');
68
+ assert.equal(confluencePageByTitleAliasPath('Release Plan', '98765'), '/confluence/pages/by-title/release-plan.json');
69
+ assert.equal(confluenceSpaceByIdAliasPath('12345'), '/confluence/spaces/by-id/12345.json');
70
+ assert.equal(confluenceByIdAliasPath('/confluence/spaces', 'ENG'), '/confluence/spaces/by-id/ENG.json');
71
+ assert.equal(confluenceByTitleAliasPath('/confluence/spaces', 'Engineering Docs', '12345'), '/confluence/spaces/by-title/engineering-docs.json');
72
+ });
73
+ it('emits a by-state alias path for canonical page statuses', () => {
74
+ assert.equal(confluencePageByStatePath('current', '98765'), '/confluence/pages/by-state/current/98765.json');
75
+ assert.equal(confluencePageByStatePath('draft', '98765'), '/confluence/pages/by-state/draft/98765.json');
76
+ assert.equal(confluencePageByStatePath('archived', '98765'), '/confluence/pages/by-state/archived/98765.json');
77
+ });
78
+ it('rejects empty status names', () => {
79
+ assert.throws(() => slugifyStatusName(' '));
80
+ });
81
+ });
82
+ describe('extractConfluenceIdFromPathSegment', () => {
83
+ it('decodes both the v2 __ separator and the legacy -- separator', () => {
84
+ assert.equal(extractConfluenceIdFromPathSegment('release-plan__98765'), '98765');
85
+ assert.equal(extractConfluenceIdFromPathSegment('release-plan--98765'), '98765');
86
+ assert.equal(extractConfluenceIdFromPathSegment('98765'), '98765');
87
+ });
88
+ });
89
+ });
90
+ //# sourceMappingURL=path-mapper.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-mapper.test.js","sourceRoot":"","sources":["../../src/__tests__/path-mapper.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=webhook-normalizer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-normalizer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/webhook-normalizer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,106 @@
1
+ import assert from 'node:assert/strict';
2
+ import { createHmac } from 'node:crypto';
3
+ import test from 'node:test';
4
+ import { CONFLUENCE_DELIVERY_HEADER, CONFLUENCE_SIGNATURE_HEADER, assertValidConfluenceWebhookSignature, computeConfluenceWebhookSignature, normalizeConfluenceWebhook, validateConfluenceWebhookSignature, validateConfluenceWebhookTimestamp, } from '../index.js';
5
+ const pagePayload = {
6
+ webhookEvent: 'page_updated',
7
+ timestamp: 1_743_155_200_000,
8
+ webhookId: 'webhook_123',
9
+ page: {
10
+ id: '98765',
11
+ title: 'Release Plan',
12
+ spaceId: '12345',
13
+ status: 'current',
14
+ },
15
+ };
16
+ test('normalizeConfluenceWebhook canonicalizes Atlassian webhookEvent and extracts subject', () => {
17
+ const normalized = normalizeConfluenceWebhook(pagePayload, {
18
+ [CONFLUENCE_DELIVERY_HEADER]: 'delivery_123',
19
+ 'X-Relay-Connection-Id': 'conn_confluence_123',
20
+ 'X-Relay-Provider-Config-Key': 'confluence',
21
+ });
22
+ assert.equal(normalized.provider, 'confluence');
23
+ assert.equal(normalized.connectionId, 'conn_confluence_123');
24
+ assert.equal(normalized.providerConfigKey, 'confluence');
25
+ assert.equal(normalized.eventType, 'page.update');
26
+ assert.equal(normalized.objectType, 'page');
27
+ assert.equal(normalized.objectId, '98765');
28
+ assert.equal(normalized.payload.id, '98765');
29
+ assert.deepEqual(normalized.payload._connection, {
30
+ connectionId: 'conn_confluence_123',
31
+ deliveryId: 'delivery_123',
32
+ provider: 'confluence',
33
+ providerConfigKey: 'confluence',
34
+ });
35
+ });
36
+ test('normalizeConfluenceWebhook handles trashed events as remove and accepts dot-notation eventType', () => {
37
+ const removed = normalizeConfluenceWebhook({
38
+ webhookEvent: 'page_trashed',
39
+ page: { id: '98765', title: 'Release Plan' },
40
+ }, {});
41
+ assert.equal(removed.eventType, 'page.remove');
42
+ const explicit = normalizeConfluenceWebhook({
43
+ eventType: 'space.update',
44
+ space: { id: '12345', name: 'Engineering' },
45
+ }, {});
46
+ assert.equal(explicit.eventType, 'space.update');
47
+ assert.equal(explicit.objectType, 'space');
48
+ assert.equal(explicit.objectId, '12345');
49
+ });
50
+ test('validateConfluenceWebhookSignature accepts the expected HMAC and rejects invalid signatures', () => {
51
+ const rawPayload = JSON.stringify(pagePayload);
52
+ const secret = 'confluence-secret';
53
+ const signature = createHmac('sha256', secret).update(rawPayload).digest('hex');
54
+ const valid = validateConfluenceWebhookSignature(rawPayload, { [CONFLUENCE_SIGNATURE_HEADER]: signature }, secret);
55
+ assert.equal(valid.ok, true);
56
+ const invalid = validateConfluenceWebhookSignature(rawPayload, { [CONFLUENCE_SIGNATURE_HEADER]: 'deadbeef' }, secret);
57
+ assert.equal(invalid.ok, false);
58
+ assert.equal(invalid.reason, 'invalid-signature');
59
+ assert.doesNotThrow(() => assertValidConfluenceWebhookSignature(rawPayload, { [CONFLUENCE_SIGNATURE_HEADER]: signature }, secret));
60
+ });
61
+ test('validateConfluenceWebhookTimestamp enforces freshness', () => {
62
+ const fresh = validateConfluenceWebhookTimestamp(pagePayload, 60_000, 1_743_155_230_000);
63
+ assert.equal(fresh.ok, true);
64
+ const stale = validateConfluenceWebhookTimestamp(pagePayload, 60_000, 1_743_155_400_001);
65
+ assert.equal(stale.ok, false);
66
+ assert.equal(stale.reason, 'stale-timestamp');
67
+ });
68
+ // Atlassian Connect sends events with a `confluence:` prefix. Make sure
69
+ // restored and archived land on the same canonical eventType as the
70
+ // un-prefixed variants — without these aliases the fallback splits the
71
+ // underscore name into `confluence:page.restored` and downstream filters
72
+ // on `page.update` miss the event entirely.
73
+ test('normalizeConfluenceWebhook resolves prefixed page_restored / page_archived to page.update', () => {
74
+ for (const event of ['confluence:page_restored', 'confluence:page_archived']) {
75
+ const normalized = normalizeConfluenceWebhook({ ...pagePayload, webhookEvent: event }, { [CONFLUENCE_DELIVERY_HEADER]: `delivery_${event}` });
76
+ assert.equal(normalized.eventType, 'page.update', `${event} should map to page.update`);
77
+ assert.equal(normalized.objectType, 'page');
78
+ }
79
+ });
80
+ // Unsupported object types must fail fast. The pre-fix code silently
81
+ // coerced anything that wasn't 'space' to 'page', which masked broken
82
+ // upstream payloads and produced bogus tree writes. Provide an
83
+ // objectId via the top-level `id` so we reach the objectType check
84
+ // rather than the missing-id guard.
85
+ test('normalizeConfluenceWebhook fails fast on unsupported object types', () => {
86
+ assert.throws(() => normalizeConfluenceWebhook({
87
+ webhookEvent: 'comment_created',
88
+ id: '111',
89
+ comment: { id: '111', text: 'hi' },
90
+ }, { [CONFLUENCE_DELIVERY_HEADER]: 'delivery_comment' }), /Unsupported Confluence webhook object type/);
91
+ });
92
+ // HMAC must compute over the provider's raw request body. Accepting a
93
+ // parsed object and JSON.stringify-ing it produced digests that drifted
94
+ // from the provider's signature whenever key ordering or whitespace
95
+ // differed. Require raw bytes (string / Buffer / Uint8Array / ArrayBuffer).
96
+ test('computeConfluenceWebhookSignature rejects parsed object payloads', () => {
97
+ assert.throws(() => computeConfluenceWebhookSignature({ webhookEvent: 'page_created' }, 'secret'), /raw request body/);
98
+ });
99
+ test('computeConfluenceWebhookSignature accepts string and Buffer raw bodies', () => {
100
+ const secret = 'shh';
101
+ const body = '{"webhookEvent":"page_created"}';
102
+ const expected = createHmac('sha256', secret).update(body).digest('hex');
103
+ assert.equal(computeConfluenceWebhookSignature(body, secret), expected);
104
+ assert.equal(computeConfluenceWebhookSignature(Buffer.from(body, 'utf8'), secret), expected);
105
+ });
106
+ //# sourceMappingURL=webhook-normalizer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-normalizer.test.js","sourceRoot":"","sources":["../../src/__tests__/webhook-normalizer.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Mirror of the Linear alias slugifier so Confluence emits identical
3
+ * `<sanitized>__<id>` and `by-title/<slug>.json` conventions advertised in
4
+ * `/confluence/LAYOUT.md`. Returns `untitled` when the input slugs to nothing
5
+ * (emoji-only / punctuation-only titles).
6
+ */
7
+ export declare function slugifyAlias(input: string): string;
8
+ export declare function aliasCollisionSuffix(id: string): string;
9
+ //# sourceMappingURL=alias-slug.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alias-slug.d.ts","sourceRoot":"","sources":["../src/alias-slug.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEvD"}
@@ -0,0 +1,23 @@
1
+ import { createHash } from 'node:crypto';
2
+ const COMBINING_MARKS_PATTERN = /[\u0300-\u036f]/g;
3
+ const MAX_ALIAS_SLUG_LENGTH = 80;
4
+ /**
5
+ * Mirror of the Linear alias slugifier so Confluence emits identical
6
+ * `<sanitized>__<id>` and `by-title/<slug>.json` conventions advertised in
7
+ * `/confluence/LAYOUT.md`. Returns `untitled` when the input slugs to nothing
8
+ * (emoji-only / punctuation-only titles).
9
+ */
10
+ export function slugifyAlias(input) {
11
+ const normalized = input
12
+ .normalize('NFKD')
13
+ .replace(COMBINING_MARKS_PATTERN, '')
14
+ .toLowerCase()
15
+ .replace(/[^a-z0-9]+/g, '-')
16
+ .slice(0, MAX_ALIAS_SLUG_LENGTH)
17
+ .replace(/^-+|-+$/g, '');
18
+ return normalized || 'untitled';
19
+ }
20
+ export function aliasCollisionSuffix(id) {
21
+ return createHash('sha256').update(id).digest('hex').slice(0, 8);
22
+ }
23
+ //# sourceMappingURL=alias-slug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alias-slug.js","sourceRoot":"","sources":["../src/alias-slug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,uBAAuB,GAAG,kBAAkB,CAAC;AACnD,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,UAAU,GAAG,KAAK;SACrB,SAAS,CAAC,MAAM,CAAC;SACjB,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC;SACpC,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC;SAC/B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAE3B,OAAO,UAAU,IAAI,UAAU,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,EAAU;IAC7C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACnE,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { ConfluencePageIndexRow, ConfluenceSpaceIndexRow } from './queries.js';
2
+ export type ConfluenceIndexBucket = 'pages' | 'spaces';
3
+ export interface ConfluenceIndexFile {
4
+ path: string;
5
+ contentType: 'application/json; charset=utf-8';
6
+ content: string;
7
+ }
8
+ export declare function buildConfluenceIndexFile(bucket: 'pages', rows: ConfluencePageIndexRow[]): ConfluenceIndexFile;
9
+ export declare function buildConfluenceIndexFile(bucket: 'spaces', rows: ConfluenceSpaceIndexRow[]): ConfluenceIndexFile;
10
+ //# sourceMappingURL=index-emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-emitter.d.ts","sourceRoot":"","sources":["../src/index-emitter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAA0B,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAE5G,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEvD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,iCAAiC,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,sBAAsB,EAAE,GAC7B,mBAAmB,CAAC;AACvB,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,uBAAuB,EAAE,GAC9B,mBAAmB,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { confluencePagesIndexPath, confluenceSpacesIndexPath, } from './path-mapper.js';
2
+ export function buildConfluenceIndexFile(bucket, rows) {
3
+ const sortedRows = [...rows].sort(compareIndexRows());
4
+ return {
5
+ path: indexPathForBucket(bucket),
6
+ contentType: 'application/json; charset=utf-8',
7
+ content: `${JSON.stringify(sortedRows)}\n`,
8
+ };
9
+ }
10
+ function indexPathForBucket(bucket) {
11
+ switch (bucket) {
12
+ case 'pages':
13
+ return confluencePagesIndexPath();
14
+ case 'spaces':
15
+ return confluenceSpacesIndexPath();
16
+ }
17
+ }
18
+ function compareIndexRows() {
19
+ return (left, right) => {
20
+ if (left.updated !== right.updated) {
21
+ return right.updated.localeCompare(left.updated);
22
+ }
23
+ return left.id.localeCompare(right.id);
24
+ };
25
+ }
26
+ //# sourceMappingURL=index-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-emitter.js","sourceRoot":"","sources":["../src/index-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAmB1B,MAAM,UAAU,wBAAwB,CACtC,MAA6B,EAC7B,IAAmC;IAEnC,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACtD,OAAO;QACL,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC;QAChC,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI;KAC3C,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,MAA6B;IACvD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO;YACV,OAAO,wBAAwB,EAAE,CAAC;QACpC,KAAK,QAAQ;YACX,OAAO,yBAAyB,EAAE,CAAC;IACvC,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB;IACvB,OAAO,CAAC,IAA4B,EAAE,KAA6B,EAAU,EAAE;QAC7E,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,17 @@
1
1
  export { ConfluenceAdapter, } from './confluence-adapter.js';
2
2
  export type { ConnectionProvider, IngestError, IngestResult, ProxyRequest, ProxyResponse, } from './confluence-adapter.js';
3
- export { CONFLUENCE_OBJECT_TYPES, computeConfluencePath, confluencePagePath, confluenceSpacePath, encodeConfluencePathSegment, extractConfluenceIdFromPathSegment, normalizeConfluenceObjectType, } from './path-mapper.js';
4
- export { CONFLUENCE_API_PAGES_ROUTE, CONFLUENCE_API_SPACES_ROUTE, resolveConfluenceReadRequest, } from './queries.js';
5
- export { resolveConfluenceDeleteRequest, resolveConfluenceWritebackRequest, } from './writeback.js';
3
+ export { CONFLUENCE_OBJECT_TYPES, CONFLUENCE_CANONICAL_PAGE_STATUSES, CONFLUENCE_PATH_ROOT, computeConfluencePath, confluenceByIdAliasPath, confluenceByTitleAliasPath, confluencePageByIdAliasPath, confluencePageByStatePath, confluencePageByTitleAliasPath, confluencePagePath, confluencePagesIndexPath, confluenceProviderRootIndexPath, confluenceSpaceByIdAliasPath, confluenceSpaceByTitleAliasPath, confluenceSpacePath, confluenceSpacesIndexPath, encodeConfluencePathSegment, extractConfluenceIdFromPathSegment, nameWithId, normalizeConfluenceObjectType, normalizeNangoConfluenceModel, parseNameWithId, slugifyStatusName, tryNormalizeConfluenceObjectType, } from './path-mapper.js';
4
+ export type { ConfluencePathObjectType, NameWithIdOptions, ParseNameWithIdResult, } from './path-mapper.js';
5
+ export { aliasCollisionSuffix, slugifyAlias, } from './alias-slug.js';
6
+ export { confluenceLayoutPromptFile, CONFLUENCE_LAYOUT_PROMPT, } from './layout-prompt.js';
7
+ export { buildConfluenceIndexFile, } from './index-emitter.js';
8
+ export type { ConfluenceIndexBucket, ConfluenceIndexFile, } from './index-emitter.js';
9
+ export { CONFLUENCE_API_SPACES_ROUTE, confluencePageIndexRow, confluenceSpaceIndexRow, getConfluencePageHumanReadable, getConfluenceSpaceHumanReadable, resolveConfluenceReadRequest, } from './queries.js';
10
+ export type { ConfluenceBaseIndexRow, ConfluencePageIndexRow, ConfluenceSpaceIndexRow, } from './queries.js';
11
+ export { CONFLUENCE_API_PAGES_ROUTE, } from './types.js';
6
12
  export type * from './types.js';
13
+ export { ReadOnlyFieldError, resolveConfluenceDeleteRequest, resolveConfluenceWritebackRequest, } from './writeback.js';
14
+ export { assertValidConfluenceWebhookSignature, computeConfluenceWebhookSignature, CONFLUENCE_DELIVERY_HEADER, CONFLUENCE_EVENT_HEADER, CONFLUENCE_PROVIDER, CONFLUENCE_SIGNATURE_HEADER, extractConfluenceConnectionMetadata, extractConfluenceEventType, extractConfluenceObjectId, extractConfluenceObjectType, normalizeConfluenceWebhook, parseConfluenceWebhookPayload, validateConfluenceWebhookSignature, validateConfluenceWebhookTimestamp, } from './webhook-normalizer.js';
15
+ export type { ConfluenceWebhookConnectionMetadata, ConfluenceWebhookHeaders, ConfluenceWebhookSignatureValidationResult, ConfluenceWebhookTimestampValidationResult, } from './webhook-normalizer.js';
7
16
  export * from './resources.js';
8
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,2BAA2B,EAC3B,kCAAkC,EAClC,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,gBAAgB,CAAC;AACxB,mBAAmB,YAAY,CAAC;AAChC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,uBAAuB,EACvB,kCAAkC,EAClC,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,EAC3B,yBAAyB,EACzB,8BAA8B,EAC9B,kBAAkB,EAClB,wBAAwB,EACxB,+BAA+B,EAC/B,4BAA4B,EAC5B,+BAA+B,EAC/B,mBAAmB,EACnB,yBAAyB,EACzB,2BAA2B,EAC3B,kCAAkC,EAClC,UAAU,EACV,6BAA6B,EAC7B,6BAA6B,EAC7B,eAAe,EACf,iBAAiB,EACjB,gCAAgC,GACjC,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,wBAAwB,EACxB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,oBAAoB,EACpB,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,2BAA2B,EAC3B,sBAAsB,EACtB,uBAAuB,EACvB,8BAA8B,EAC9B,+BAA+B,EAC/B,4BAA4B,GAC7B,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,0BAA0B,GAC3B,MAAM,YAAY,CAAC;AACpB,mBAAmB,YAAY,CAAC;AAEhC,OAAO,EACL,kBAAkB,EAClB,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,qCAAqC,EACrC,iCAAiC,EACjC,0BAA0B,EAC1B,uBAAuB,EACvB,mBAAmB,EACnB,2BAA2B,EAC3B,mCAAmC,EACnC,0BAA0B,EAC1B,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,6BAA6B,EAC7B,kCAAkC,EAClC,kCAAkC,GACnC,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,mCAAmC,EACnC,wBAAwB,EACxB,0CAA0C,EAC1C,0CAA0C,GAC3C,MAAM,yBAAyB,CAAC;AAEjC,cAAc,gBAAgB,CAAC"}