@ganju/utils 0.0.14 → 0.0.16

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 (111) hide show
  1. package/dist/channelCustomer.d.ts +99 -0
  2. package/dist/channelCustomer.d.ts.map +1 -0
  3. package/dist/channelCustomer.js +533 -0
  4. package/dist/channelDebounce.d.ts +7 -0
  5. package/dist/channelDebounce.d.ts.map +1 -1
  6. package/dist/chunkOverlap.d.ts +2 -0
  7. package/dist/chunkOverlap.d.ts.map +1 -0
  8. package/dist/chunkOverlap.js +9 -0
  9. package/dist/chunking.d.ts.map +1 -1
  10. package/dist/chunking.js +24 -4
  11. package/dist/citations.d.ts +28 -0
  12. package/dist/citations.d.ts.map +1 -0
  13. package/dist/citations.js +111 -0
  14. package/dist/constants.d.ts +49 -0
  15. package/dist/constants.d.ts.map +1 -1
  16. package/dist/constants.js +202 -17
  17. package/dist/data.d.ts +9 -0
  18. package/dist/data.d.ts.map +1 -0
  19. package/dist/data.js +78 -0
  20. package/dist/dataApi.d.ts +511 -0
  21. package/dist/dataApi.d.ts.map +1 -0
  22. package/dist/dataApi.js +355 -0
  23. package/dist/dataCompiler.d.ts +68 -0
  24. package/dist/dataCompiler.d.ts.map +1 -0
  25. package/dist/dataCompiler.js +726 -0
  26. package/dist/dataDdl.d.ts +29 -0
  27. package/dist/dataDdl.d.ts.map +1 -0
  28. package/dist/dataDdl.js +354 -0
  29. package/dist/dataEngine.d.ts +143 -0
  30. package/dist/dataEngine.d.ts.map +1 -0
  31. package/dist/dataEngine.js +2022 -0
  32. package/dist/dataIdentifiers.d.ts +8 -0
  33. package/dist/dataIdentifiers.d.ts.map +1 -0
  34. package/dist/dataIdentifiers.js +55 -0
  35. package/dist/dataImport.d.ts +77 -0
  36. package/dist/dataImport.d.ts.map +1 -0
  37. package/dist/dataImport.js +450 -0
  38. package/dist/dataRpc.d.ts +131 -0
  39. package/dist/dataRpc.d.ts.map +1 -0
  40. package/dist/dataRpc.js +2 -0
  41. package/dist/dataTypes.d.ts +157 -0
  42. package/dist/dataTypes.d.ts.map +1 -0
  43. package/dist/dataTypes.js +160 -0
  44. package/dist/index.d.ts +570 -36
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +72 -0
  47. package/dist/jsonSchemaToZodShape.d.ts +5 -1
  48. package/dist/jsonSchemaToZodShape.d.ts.map +1 -1
  49. package/dist/jsonSchemaToZodShape.js +21 -9
  50. package/dist/oauth.d.ts +14 -0
  51. package/dist/oauth.d.ts.map +1 -1
  52. package/dist/oauth.js +42 -2
  53. package/dist/pagination.d.ts +47 -0
  54. package/dist/pagination.d.ts.map +1 -0
  55. package/dist/pagination.js +160 -0
  56. package/dist/processQueueBatch.d.ts +6 -1
  57. package/dist/processQueueBatch.d.ts.map +1 -1
  58. package/dist/processQueueBatch.js +23 -10
  59. package/dist/queueFailure.d.ts +14 -0
  60. package/dist/queueFailure.d.ts.map +1 -0
  61. package/dist/queueFailure.js +43 -0
  62. package/dist/resourceRerank.d.ts +3 -2
  63. package/dist/resourceRerank.d.ts.map +1 -1
  64. package/dist/resourceRerank.js +8 -3
  65. package/dist/schema.d.ts +374 -29
  66. package/dist/schema.d.ts.map +1 -1
  67. package/dist/schema.js +290 -6
  68. package/dist/ssrf.d.ts +1 -0
  69. package/dist/ssrf.d.ts.map +1 -1
  70. package/dist/ssrf.js +48 -12
  71. package/dist/toolConfirmation.d.ts +48 -0
  72. package/dist/toolConfirmation.d.ts.map +1 -1
  73. package/dist/toolConfirmation.js +75 -1
  74. package/dist/toolCount.d.ts +13 -0
  75. package/dist/toolCount.d.ts.map +1 -0
  76. package/dist/toolCount.js +45 -0
  77. package/dist/toolLint.d.ts +1 -1
  78. package/dist/toolLint.d.ts.map +1 -1
  79. package/dist/toolLint.js +20 -0
  80. package/dist/untrustedContent.d.ts +135 -0
  81. package/dist/untrustedContent.d.ts.map +1 -0
  82. package/dist/untrustedContent.js +402 -0
  83. package/package.json +17 -1
  84. package/src/channelCustomer.ts +604 -0
  85. package/src/channelDebounce.ts +17 -0
  86. package/src/chunkOverlap.ts +6 -0
  87. package/src/chunking.ts +25 -4
  88. package/src/citations.ts +127 -0
  89. package/src/constants.ts +219 -17
  90. package/src/data.ts +74 -0
  91. package/src/dataApi.ts +428 -0
  92. package/src/dataCompiler.ts +948 -0
  93. package/src/dataDdl.ts +419 -0
  94. package/src/dataEngine.ts +2753 -0
  95. package/src/dataIdentifiers.ts +63 -0
  96. package/src/dataImport.ts +554 -0
  97. package/src/dataRpc.ts +121 -0
  98. package/src/dataTypes.ts +312 -0
  99. package/src/index.ts +156 -2
  100. package/src/jsonSchemaToZodShape.ts +31 -13
  101. package/src/oauth.ts +42 -1
  102. package/src/pagination.ts +193 -0
  103. package/src/processQueueBatch.ts +42 -12
  104. package/src/queueFailure.ts +63 -0
  105. package/src/resourceRerank.ts +10 -3
  106. package/src/schema.ts +346 -4
  107. package/src/ssrf.ts +40 -11
  108. package/src/toolConfirmation.ts +123 -0
  109. package/src/toolCount.ts +53 -0
  110. package/src/toolLint.ts +27 -0
  111. package/src/untrustedContent.ts +476 -0
package/dist/constants.js CHANGED
@@ -104,6 +104,10 @@ const OAUTH_TOKEN_URLS = {
104
104
  // expire mid-flight. Shared by every credential-refresh path (native OAuth and
105
105
  // MCP-proxy OAuth, in both apps/api and apps/mcp).
106
106
  const CREDENTIAL_REFRESH_BUFFER_MS = 60 * 1000;
107
+ // A refresh the token endpoint rejects (4xx) without a reauth code still flags
108
+ // the credential once its access token has been expired this long, so the
109
+ // owner sees it as expired instead of every call failing behind "Connected".
110
+ const CREDENTIAL_REFRESH_GIVE_UP_MS = 60 * 60 * 1000;
107
111
  const GOOGLE_CALENDAR_API_BASE = 'https://www.googleapis.com/calendar/v3';
108
112
  const GOOGLE_DRIVE_API_BASE = 'https://www.googleapis.com/drive/v3';
109
113
  const GOOGLE_DRIVE_DEFAULT_PAGE_SIZE = 200;
@@ -167,7 +171,17 @@ const ONE_DRIVE_TAB_LABELS = [
167
171
  { value: ONE_DRIVE_TAB_RECENT, label: ONE_DRIVE_TAB_LABEL_RECENT },
168
172
  { value: ONE_DRIVE_TAB_DRIVES, label: ONE_DRIVE_TAB_LABEL_DRIVES }
169
173
  ];
170
- const REAUTH_ERROR_CODES = ['invalid_grant', 'invalid_token'];
174
+ // Token-endpoint error codes that mean the stored refresh token is dead and
175
+ // only a reconnect brings it back. `unauthorized_client` is Google's answer
176
+ // when a token no longer belongs to the app it is refreshed with.
177
+ const REAUTH_ERROR_CODES = [
178
+ 'invalid_grant',
179
+ 'invalid_token',
180
+ 'unauthorized_client'
181
+ ];
182
+ // Token-endpoint error codes that are about our own client id / secret, not
183
+ // the user's token: a reconnect can't fix them, so they never flag one.
184
+ const OAUTH_CLIENT_ERROR_CODES = ['invalid_client'];
171
185
  const RESOURCE_TYPE_TOOLTIP_MIN_WIDTH = 300;
172
186
  const SEARCH_DEBOUNCE_MS = 300;
173
187
  const SCHEMA_DEFINITION_TYPES = [
@@ -252,6 +266,9 @@ const CRAWL_MAX_PAGES_LIMIT = 1000;
252
266
  const CRAWL_DEFAULT_MAX_DEPTH = 3;
253
267
  const CRAWL_MAX_DEPTH_LIMIT = 10;
254
268
  const CRAWL_PAGE_FETCH_TIMEOUT_MS = 30000;
269
+ // Redirects one crawl fetch may follow. Each hop is screened on its own, so a
270
+ // public URL can't bounce the crawler onto a private address.
271
+ const CRAWL_MAX_REDIRECTS = 5;
255
272
  const CRAWL_USER_AGENT = 'Mozilla/5.0 (compatible; GanjuCrawler/1.0; +https://ganju.ai)';
256
273
  const CRAWL_PAGE_QUEUE_BATCH_SIZE = 100;
257
274
  const RESOURCE_ICON_THEME_DARK = 'dark';
@@ -484,6 +501,10 @@ const RATE_LIMIT_BACKOFF_SECONDS = 60;
484
501
  // Short backoff for transient Cloudflare platform errors (e.g. a Durable Object
485
502
  // / Container reset) so the retried job lands after the object has recovered.
486
503
  const TRANSIENT_BACKOFF_SECONDS = 5;
504
+ // Retries every resource queue consumer is configured with (`max_retries` in
505
+ // the API worker's wrangler config). A job's last delivery is attempt
506
+ // QUEUE_MAX_RETRIES + 1; only then is its work marked failed.
507
+ const QUEUE_MAX_RETRIES = 3;
487
508
  const CHANNEL_PLATFORM_TELEGRAM = 'telegram';
488
509
  const CHANNEL_PLATFORM_SLACK = 'slack';
489
510
  const CHANNEL_PLATFORM_WHATSAPP = 'whatsapp';
@@ -667,14 +688,37 @@ const TOOL_CONFIRMATION_ASK_INSTRUCTION = 'IMPORTANT: these actions have NOT bee
667
688
  'confirm, and must not say or suggest that they were done, nor describe ' +
668
689
  'or make up any result from them.';
669
690
  // For MCP clients, whose chat the server can't see: a sensitive call without a
670
- // valid confirmation isn't run, and the model is told to ask the user and call
671
- // again with a token that binds the second call to these exact arguments.
672
- // How long that token stays good, and the argument that carries it.
691
+ // valid confirmation isn't run. Ordinarily the model is told to ask the user
692
+ // and call again with a token that binds the second call to these exact
693
+ // arguments; once the session has read outside content, the user approves it
694
+ // on a dashboard page instead, and the second call carries that approval's
695
+ // id. How long either stays good, and the argument that carries it.
673
696
  const MCP_TOOL_CONFIRMATION_TTL_MS = 10 * 60 * 1000;
674
697
  const MCP_TOOL_CONFIRMATION_ARG = 'confirmation';
675
698
  const MCP_TOOL_CONFIRMATION_ARG_DESCRIPTION = "Leave out on the first call. This action needs the user's yes: the " +
676
- 'first call returns a token; after the user says yes, call again with the ' +
677
- 'same arguments and that token here.';
699
+ 'first call returns a code and says how to get that yes; once the user ' +
700
+ 'has given it, call again with the same arguments and that code here.';
701
+ // The same argument where only some calls ask: those made after the session
702
+ // read outside content.
703
+ const MCP_TOOL_CONFIRMATION_ARG_DESCRIPTION_CONDITIONAL = "Leave out on the first call. If this action needs the user's yes, the " +
704
+ 'first call returns a code instead of running and says how to get that ' +
705
+ 'yes; once the user has given it, call again with the same arguments and ' +
706
+ 'that code here.';
707
+ // The dashboard page where a signed-in user approves or denies one such call,
708
+ // as `${TOOL_APPROVAL_PATH}/<approval id>`, and the two answers it sends.
709
+ const TOOL_APPROVAL_PATH = '/tool-approval';
710
+ const TOOL_APPROVAL_DECISION_APPROVE = 'approve';
711
+ const TOOL_APPROVAL_DECISION_DENY = 'deny';
712
+ const TOOL_APPROVAL_DECISIONS = [
713
+ TOOL_APPROVAL_DECISION_APPROVE,
714
+ TOOL_APPROVAL_DECISION_DENY
715
+ ];
716
+ // Where an approval stands, as the page shows it.
717
+ const TOOL_APPROVAL_STATUS_PENDING = 'pending';
718
+ const TOOL_APPROVAL_STATUS_APPROVED = 'approved';
719
+ const TOOL_APPROVAL_STATUS_DENIED = 'denied';
720
+ const TOOL_APPROVAL_STATUS_USED = 'used';
721
+ const TOOL_APPROVAL_STATUS_EXPIRED = 'expired';
678
722
  // The question when the model wrote none, above the runner's own summary.
679
723
  const TOOL_CONFIRMATION_FALLBACK_QUESTION = 'Before I do this, please confirm. Reply yes to go ahead, or no to cancel.';
680
724
  const TELEGRAM_SECRET_HEADER = 'x-telegram-bot-api-secret-token';
@@ -695,13 +739,15 @@ const SLACK_MESSAGE_LIMIT = 2900;
695
739
  const SLACK_MAX_SOURCE_BUTTONS = 10;
696
740
  // The Slack app configuration Ganju needs, surfaced in the UI when connecting a
697
741
  // Slack channel. Required scopes back the runner's calls (mentions, DMs,
698
- // posting, file upload); recommended scopes only enrich names/titles and
699
- // degrade gracefully; bot events are what the webhook subscribes to.
742
+ // posting, file upload, downloading a voice clip to transcribe it);
743
+ // recommended scopes only enrich names/titles and degrade gracefully; bot
744
+ // events are what the webhook subscribes to.
700
745
  const SLACK_REQUIRED_SCOPES = [
701
746
  'app_mentions:read',
702
747
  'im:history',
703
748
  'chat:write',
704
- 'files:write'
749
+ 'files:write',
750
+ 'files:read'
705
751
  ];
706
752
  const SLACK_RECOMMENDED_SCOPES = ['users:read', 'channels:read', 'groups:read'];
707
753
  const SLACK_BOT_EVENTS = ['app_mention', 'message.im'];
@@ -808,12 +854,29 @@ const RESOURCE_SEARCH_RRF_K = 60;
808
854
  // keeps its words.
809
855
  const RESOURCE_SEARCH_COMMON_TERM_DIVISOR = 10;
810
856
  const RESOURCE_SEARCH_COMMON_TERM_MIN = 5;
811
- // Second stage, on wherever the Worker has an AI binding: the top fused
812
- // candidates are re-scored by a cross-encoder, which reads query and chunk
813
- // together instead of comparing two independently computed vectors. One model
814
- // call per search; a failure falls back to the fused order.
857
+ // Second stage: the top fused candidates re-scored by a cross-encoder, which
858
+ // reads query and chunk together instead of comparing two independently
859
+ // computed vectors. One model call per search; a failure falls back to the
860
+ // fused order. Off by default: on the golden sets (Spanish and English) the
861
+ // fused order matched or beat it on every set — 10 cases better, 5 worse — and
862
+ // it added 0.5–0.9 s a search plus a ~6 s cold start. The search eval can
863
+ // still turn it on per request to re-measure.
864
+ const RESOURCE_SEARCH_RERANK_ENABLED = false;
815
865
  const RESOURCE_SEARCH_RERANK_CANDIDATES = 30;
816
866
  const RESOURCE_SEARCH_RERANK_MODEL = '@cf/baai/bge-reranker-base';
867
+ // An identifier in the query (a code mixing letters and digits, a snake_case
868
+ // name, or a number, dotted or hyphenated name typed on its own) found in at
869
+ // most this many documents is what the user is after: its chunks go first,
870
+ // whatever the reranker thinks. A cross-encoder reads "86400" or "PGRST116" as noise and
871
+ // would bury the one chunk that contains it under pages that merely look
872
+ // related. Past EXACT_MAX_CHUNKS matching chunks the identifier is common
873
+ // enough that the usual ranking is left to decide, and the scan stops there.
874
+ const RESOURCE_SEARCH_EXACT_MAX_RESOURCES = 5;
875
+ const RESOURCE_SEARCH_EXACT_MAX_CHUNKS = 30;
876
+ // An identifier the index never saw is looked for as plain text, which reads
877
+ // every chunk of the artifact when nothing matches. Past this many chunks that
878
+ // costs more than the rare hit is worth, so a large artifact skips it.
879
+ const RESOURCE_SEARCH_SUBSTRING_MAX_CHUNKS = 20000;
817
880
  const RESOURCE_HANDLER_SLEEP_AFTER = '10m';
818
881
  const DOCS_URL = 'https://ganju.ai/docs/';
819
882
  const BASE64_DATA_URI_RE = /data:image\/[a-zA-Z0-9+\-.]+;base64,[A-Za-z0-9+/=\s]+/g;
@@ -826,6 +889,11 @@ const CHUNK_SEPARATORS = [
826
889
  { split: ' ', join: ' ' }
827
890
  ];
828
891
  const DEFAULT_MAX_TOKENS = 4096;
892
+ // One page of `list-resources`. A knowledge base with a crawled site runs to
893
+ // thousands of resources; listed whole, that is one result of several hundred
894
+ // KB in the model's context.
895
+ const LIST_RESOURCES_DEFAULT_LIMIT = 100;
896
+ const LIST_RESOURCES_MAX_LIMIT = 500;
829
897
  const RESOURCE_TOOL_KEY_LIST_RESOURCES = 'list-resources';
830
898
  const RESOURCE_TOOL_KEY_SEARCH_RESOURCES = 'search-resources';
831
899
  const RESOURCE_TOOL_KEY_READ_RESOURCE = 'read-resource';
@@ -1288,7 +1356,9 @@ const RESERVED_TOOL_NAMES = [
1288
1356
  TOOL_DEFINITION_KEY_HTTP_ENDPOINT,
1289
1357
  TOOL_DEFINITION_KEY_MCP_PROXY,
1290
1358
  TOOL_DEFINITION_KEY_CUSTOM_CODE,
1291
- sdkConstants_1.CUSTOM_CODE_HEALTH_TOOL
1359
+ sdkConstants_1.CUSTOM_CODE_HEALTH_TOOL,
1360
+ // The channel runner's own memory tool (PARTICIPANT_MEMORY_TOOL_NAME).
1361
+ 'remember-customer'
1292
1362
  ];
1293
1363
  // Shared by both write paths so there is one string to translate. It has to
1294
1364
  // carry a word `matchStatus` recognises (errorHandler.ts), because the
@@ -1516,8 +1586,16 @@ const MCP_AUTH_KIND_INTERNAL = 'internal';
1516
1586
  const MCP_AUTH_KINDS = [MCP_AUTH_KIND_JWT, MCP_AUTH_KIND_INTERNAL];
1517
1587
  const MCP_SESSION_HEADER = 'mcp-session-id';
1518
1588
  const MCP_INTERNAL_HEADER = 'x-ganju-internal-secret';
1589
+ // Sent with the internal secret by the search eval to measure the reranker:
1590
+ // `on` or `off` overrides RESOURCE_SEARCH_RERANK_ENABLED for that request.
1591
+ // Ignored on any other request.
1592
+ const MCP_EVAL_RERANK_HEADER = 'x-ganju-eval-rerank';
1519
1593
  const MCP_CHANNEL_ID_HEADER = 'x-ganju-channel-id';
1520
1594
  const MCP_CHANNEL_PLATFORM_HEADER = 'x-ganju-channel-platform';
1595
+ // The conversation a channel turn belongs to. The MCP worker files that turn's
1596
+ // calls under one session per conversation, so a call can be traced back to
1597
+ // the chat it ran in.
1598
+ const MCP_CHANNEL_CONVERSATION_HEADER = 'x-ganju-channel-conversation-id';
1521
1599
  const MCP_CHANNEL_CLIENT_USER_AGENT = 'ganju-channel/0.0.1';
1522
1600
  const JWKS_KV_KEY = 'jwks:v1';
1523
1601
  const JWKS_TTL_SECONDS = 600;
@@ -1604,6 +1682,22 @@ const ACCESS_TOKEN_SCOPE_MESSAGE = 'This token is scoped to a different project'
1604
1682
  // Recent custom-tool invocations, as `ganju logs` reads them.
1605
1683
  const CUSTOM_CODE_LOGS_DEFAULT_LIMIT = 20;
1606
1684
  const CUSTOM_CODE_LOGS_MAX_LIMIT = 100;
1685
+ // Tool observability on the project home. The windows match the activity
1686
+ // chart's, and none reaches past `RETENTION_DAYS.mcpRequest`.
1687
+ const OBSERVABILITY_RANGE_DAYS = [7, 30, 90];
1688
+ // An enabled tool with no call in this many days is offered for disabling.
1689
+ const OBSERVABILITY_UNUSED_DAYS = 30;
1690
+ // Two calls in one session this close together are one attempt followed by
1691
+ // the next: a retry when it's the same tool, a switch when it's another tool
1692
+ // after an error.
1693
+ const OBSERVABILITY_FOLLOW_UP_SECONDS = 120;
1694
+ // How a call rejected by its tool's input schema reads in `error_message`.
1695
+ const OBSERVABILITY_SCHEMA_REJECTION_PREFIX = 'Input validation error';
1696
+ const OBSERVABILITY_TOP_ERRORS = 8;
1697
+ const OBSERVABILITY_CALLS_DEFAULT_LIMIT = 25;
1698
+ const OBSERVABILITY_CALLS_MAX_LIMIT = 100;
1699
+ // A session timeline is read whole up to this many calls, newest kept.
1700
+ const OBSERVABILITY_SESSION_MAX_CALLS = 500;
1607
1701
  const BOT_GRANT_TYPE = 'urn:ganju:bot-on-behalf-of';
1608
1702
  const EXTERNAL_LINK_VERIFICATION_PREFIX = 'external_link:';
1609
1703
  const EXTERNAL_LINK_TTL_SECONDS = 600;
@@ -1764,6 +1858,39 @@ const PRICING_TOOL_CALL_PER_M_USD = 5;
1764
1858
  // million calls a month, so a fixed ceiling there would fight a real customer.
1765
1859
  const PRICING_TOOL_CALL_HARD_CAP = 20_000_000;
1766
1860
  const PRICING_CUSTOM_DOMAIN_USD = 15;
1861
+ // Project data (one SQLite Durable Object per artifact). Cloudflare caps a
1862
+ // database at 10 GB; we stop writes that add data at 9 GB so there is room to
1863
+ // delete, archive and export.
1864
+ const DATA_MAX_DATABASE_BYTES = 9 * GB;
1865
+ const DATA_MAX_TABLES_PER_DATABASE = 50;
1866
+ const DATA_TRIGGER_RUN_HARD_CAP = 5_000_000;
1867
+ // A deleted database can be restored for this long before its storage is
1868
+ // freed.
1869
+ const DATA_DELETE_GRACE_DAYS = 7;
1870
+ const ARTIFACT_DATABASE_STATUS_CREATING = 'CREATING';
1871
+ const ARTIFACT_DATABASE_STATUS_READY = 'READY';
1872
+ const ARTIFACT_DATABASE_STATUS_FAILED = 'FAILED';
1873
+ const ARTIFACT_DATABASE_STATUS_DELETING = 'DELETING';
1874
+ // The hourly purge has claimed the row and is emptying the object; a restore
1875
+ // can no longer take it back.
1876
+ const ARTIFACT_DATABASE_STATUS_PURGING = 'PURGING';
1877
+ const ARTIFACT_DATABASE_STATUS_DELETED = 'DELETED';
1878
+ const ARTIFACT_DATABASE_STATUSES = [
1879
+ ARTIFACT_DATABASE_STATUS_CREATING,
1880
+ ARTIFACT_DATABASE_STATUS_READY,
1881
+ ARTIFACT_DATABASE_STATUS_FAILED,
1882
+ ARTIFACT_DATABASE_STATUS_DELETING,
1883
+ ARTIFACT_DATABASE_STATUS_PURGING,
1884
+ ARTIFACT_DATABASE_STATUS_DELETED
1885
+ ];
1886
+ // A purge that claimed a row and never finished (the Worker died) is picked
1887
+ // up again after this long.
1888
+ const DATA_PURGE_STALE_MS = 60 * 60 * 1000;
1889
+ // Rows purged per hourly run: each is a call to its database object.
1890
+ const DATA_PURGE_BATCH = 20;
1891
+ // last_read_at / last_write_at move at most this often, so they aren't a
1892
+ // Postgres write per query.
1893
+ const DATA_ACTIVITY_THROTTLE_MS = 60 * 60 * 1000;
1767
1894
  const PLAN_LIMITS = {
1768
1895
  FREE: {
1769
1896
  maxProjects: 1,
@@ -1799,7 +1926,11 @@ const PLAN_LIMITS = {
1799
1926
  toolCallHardCap: 10_000,
1800
1927
  includedMessages: 100,
1801
1928
  includedEmbeddedBytes: 5 * MB,
1802
- autoSyncIntervals: []
1929
+ autoSyncIntervals: [],
1930
+ canUseData: false,
1931
+ maxDataBytes: null,
1932
+ maxDataTablesPerDatabase: null,
1933
+ triggerRunHardCap: 0
1803
1934
  },
1804
1935
  PRO: {
1805
1936
  maxProjects: null,
@@ -1826,7 +1957,11 @@ const PLAN_LIMITS = {
1826
1957
  autoSyncIntervals: [
1827
1958
  RESOURCE_SYNC_INTERVAL_DAILY,
1828
1959
  RESOURCE_SYNC_INTERVAL_WEEKLY
1829
- ]
1960
+ ],
1961
+ canUseData: true,
1962
+ maxDataBytes: DATA_MAX_DATABASE_BYTES,
1963
+ maxDataTablesPerDatabase: DATA_MAX_TABLES_PER_DATABASE,
1964
+ triggerRunHardCap: DATA_TRIGGER_RUN_HARD_CAP
1830
1965
  },
1831
1966
  ENTERPRISE: {
1832
1967
  maxProjects: null,
@@ -1853,7 +1988,11 @@ const PLAN_LIMITS = {
1853
1988
  autoSyncIntervals: [
1854
1989
  RESOURCE_SYNC_INTERVAL_DAILY,
1855
1990
  RESOURCE_SYNC_INTERVAL_WEEKLY
1856
- ]
1991
+ ],
1992
+ canUseData: true,
1993
+ maxDataBytes: DATA_MAX_DATABASE_BYTES,
1994
+ maxDataTablesPerDatabase: DATA_MAX_TABLES_PER_DATABASE,
1995
+ triggerRunHardCap: null
1857
1996
  }
1858
1997
  };
1859
1998
  // Quota features — used as the `feature` discriminator on PlanLimitError so the
@@ -1872,6 +2011,7 @@ const PLAN_FEATURE_EMBEDDED_STORAGE = 'embeddedStorage';
1872
2011
  const PLAN_FEATURE_MESSAGE = 'message';
1873
2012
  const PLAN_FEATURE_TOOL_CALL = 'toolCall';
1874
2013
  const PLAN_FEATURE_RESOURCE_SYNC = 'resourceSync';
2014
+ const PLAN_FEATURE_DATA = 'data';
1875
2015
  // Stable code returned on a quota block so clients can branch on it (402).
1876
2016
  const PLAN_LIMIT_ERROR_CODE = 'PLAN_LIMIT_EXCEEDED';
1877
2017
  // Billing meter event names. The metering cron reports per-period OVERAGE
@@ -2026,6 +2166,20 @@ exports.constants = {
2026
2166
  PRICING_TOOL_CALL_PER_M_USD,
2027
2167
  PRICING_TOOL_CALL_HARD_CAP,
2028
2168
  PRICING_CUSTOM_DOMAIN_USD,
2169
+ DATA_MAX_DATABASE_BYTES,
2170
+ DATA_MAX_TABLES_PER_DATABASE,
2171
+ DATA_TRIGGER_RUN_HARD_CAP,
2172
+ DATA_DELETE_GRACE_DAYS,
2173
+ DATA_PURGE_BATCH,
2174
+ DATA_ACTIVITY_THROTTLE_MS,
2175
+ ARTIFACT_DATABASE_STATUS_CREATING,
2176
+ ARTIFACT_DATABASE_STATUS_READY,
2177
+ ARTIFACT_DATABASE_STATUS_FAILED,
2178
+ ARTIFACT_DATABASE_STATUS_DELETING,
2179
+ ARTIFACT_DATABASE_STATUS_PURGING,
2180
+ ARTIFACT_DATABASE_STATUS_DELETED,
2181
+ DATA_PURGE_STALE_MS,
2182
+ ARTIFACT_DATABASE_STATUSES,
2029
2183
  PLAN_FEATURE_ORGANIZATION,
2030
2184
  PLAN_FEATURE_PROJECT,
2031
2185
  PLAN_FEATURE_TOOL,
@@ -2040,6 +2194,7 @@ exports.constants = {
2040
2194
  PLAN_FEATURE_MESSAGE,
2041
2195
  PLAN_FEATURE_TOOL_CALL,
2042
2196
  PLAN_FEATURE_RESOURCE_SYNC,
2197
+ PLAN_FEATURE_DATA,
2043
2198
  PLAN_LIMIT_ERROR_CODE,
2044
2199
  BILLING_METER_MESSAGES,
2045
2200
  BILLING_METER_SHARED_MESSAGES,
@@ -2128,6 +2283,7 @@ exports.constants = {
2128
2283
  SLACK_OAUTH_TOKEN_URL,
2129
2284
  OAUTH_TOKEN_URLS,
2130
2285
  CREDENTIAL_REFRESH_BUFFER_MS,
2286
+ CREDENTIAL_REFRESH_GIVE_UP_MS,
2131
2287
  GOOGLE_CALENDAR_API_BASE,
2132
2288
  GOOGLE_DRIVE_API_BASE,
2133
2289
  GOOGLE_DRIVE_DEFAULT_PAGE_SIZE,
@@ -2163,6 +2319,7 @@ exports.constants = {
2163
2319
  ONE_DRIVE_TAB_LABEL_DRIVES,
2164
2320
  ONE_DRIVE_TAB_LABELS,
2165
2321
  REAUTH_ERROR_CODES,
2322
+ OAUTH_CLIENT_ERROR_CODES,
2166
2323
  RESOURCE_TYPE_TOOLTIP_MIN_WIDTH,
2167
2324
  SEARCH_DEBOUNCE_MS,
2168
2325
  GOOGLE_DRIVE_EXPORT_MIME_TYPES,
@@ -2251,6 +2408,7 @@ exports.constants = {
2251
2408
  CRAWL_DEFAULT_MAX_DEPTH,
2252
2409
  CRAWL_MAX_DEPTH_LIMIT,
2253
2410
  CRAWL_PAGE_FETCH_TIMEOUT_MS,
2411
+ CRAWL_MAX_REDIRECTS,
2254
2412
  CRAWL_PAGE_QUEUE_BATCH_SIZE,
2255
2413
  CRAWL_USER_AGENT,
2256
2414
  RESOURCE_ICON_THEME_DARK,
@@ -2268,6 +2426,7 @@ exports.constants = {
2268
2426
  TELEGRAM_MAX_FILE_BYTES,
2269
2427
  RATE_LIMIT_BACKOFF_SECONDS,
2270
2428
  TRANSIENT_BACKOFF_SECONDS,
2429
+ QUEUE_MAX_RETRIES,
2271
2430
  ENCODINGS,
2272
2431
  ENCODING_UTF8,
2273
2432
  CHANNEL_PLATFORM_TELEGRAM,
@@ -2309,6 +2468,16 @@ exports.constants = {
2309
2468
  MCP_TOOL_CONFIRMATION_TTL_MS,
2310
2469
  MCP_TOOL_CONFIRMATION_ARG,
2311
2470
  MCP_TOOL_CONFIRMATION_ARG_DESCRIPTION,
2471
+ MCP_TOOL_CONFIRMATION_ARG_DESCRIPTION_CONDITIONAL,
2472
+ TOOL_APPROVAL_PATH,
2473
+ TOOL_APPROVAL_DECISION_APPROVE,
2474
+ TOOL_APPROVAL_DECISION_DENY,
2475
+ TOOL_APPROVAL_DECISIONS,
2476
+ TOOL_APPROVAL_STATUS_PENDING,
2477
+ TOOL_APPROVAL_STATUS_APPROVED,
2478
+ TOOL_APPROVAL_STATUS_DENIED,
2479
+ TOOL_APPROVAL_STATUS_USED,
2480
+ TOOL_APPROVAL_STATUS_EXPIRED,
2312
2481
  CHANNEL_DEBOUNCE_DEFAULT_MS,
2313
2482
  CHANNEL_DEBOUNCE_MIN_MS,
2314
2483
  CHANNEL_DEBOUNCE_MAX_MS,
@@ -2379,8 +2548,12 @@ exports.constants = {
2379
2548
  RESOURCE_SEARCH_RRF_K,
2380
2549
  RESOURCE_SEARCH_COMMON_TERM_DIVISOR,
2381
2550
  RESOURCE_SEARCH_COMMON_TERM_MIN,
2551
+ RESOURCE_SEARCH_RERANK_ENABLED,
2382
2552
  RESOURCE_SEARCH_RERANK_CANDIDATES,
2383
2553
  RESOURCE_SEARCH_RERANK_MODEL,
2554
+ RESOURCE_SEARCH_EXACT_MAX_RESOURCES,
2555
+ RESOURCE_SEARCH_EXACT_MAX_CHUNKS,
2556
+ RESOURCE_SEARCH_SUBSTRING_MAX_CHUNKS,
2384
2557
  RESOURCE_HANDLER_SLEEP_AFTER,
2385
2558
  DOCS_URL,
2386
2559
  BASE64_DATA_URI_RE,
@@ -2388,6 +2561,8 @@ exports.constants = {
2388
2561
  CHUNK_SEPARATORS,
2389
2562
  DEFAULT_MAX_TOKENS,
2390
2563
  RESOURCE_TOOL_KEY_LIST_RESOURCES,
2564
+ LIST_RESOURCES_DEFAULT_LIMIT,
2565
+ LIST_RESOURCES_MAX_LIMIT,
2391
2566
  RESOURCE_TOOL_KEY_SEARCH_RESOURCES,
2392
2567
  RESOURCE_TOOL_KEY_READ_RESOURCE,
2393
2568
  RESOURCE_TOOL_KEY_SEND_RESOURCE,
@@ -2559,8 +2734,10 @@ exports.constants = {
2559
2734
  CUSTOM_CODE_RESOURCE_FILE_TOO_LARGE_MESSAGE,
2560
2735
  RESERVED_SLUGS,
2561
2736
  MCP_INTERNAL_HEADER,
2737
+ MCP_EVAL_RERANK_HEADER,
2562
2738
  MCP_CHANNEL_ID_HEADER,
2563
2739
  MCP_CHANNEL_PLATFORM_HEADER,
2740
+ MCP_CHANNEL_CONVERSATION_HEADER,
2564
2741
  MCP_CHANNEL_CLIENT_USER_AGENT,
2565
2742
  MCP_SESSION_HEADER,
2566
2743
  MCP_REQUEST_METHOD_INITIALIZE,
@@ -2598,6 +2775,14 @@ exports.constants = {
2598
2775
  ACCESS_TOKEN_SCOPE_MESSAGE,
2599
2776
  CUSTOM_CODE_LOGS_DEFAULT_LIMIT,
2600
2777
  CUSTOM_CODE_LOGS_MAX_LIMIT,
2778
+ OBSERVABILITY_RANGE_DAYS,
2779
+ OBSERVABILITY_UNUSED_DAYS,
2780
+ OBSERVABILITY_FOLLOW_UP_SECONDS,
2781
+ OBSERVABILITY_SCHEMA_REJECTION_PREFIX,
2782
+ OBSERVABILITY_TOP_ERRORS,
2783
+ OBSERVABILITY_CALLS_DEFAULT_LIMIT,
2784
+ OBSERVABILITY_CALLS_MAX_LIMIT,
2785
+ OBSERVABILITY_SESSION_MAX_CALLS,
2601
2786
  BOT_GRANT_TYPE,
2602
2787
  EXTERNAL_LINK_VERIFICATION_PREFIX,
2603
2788
  EXTERNAL_LINK_TTL_SECONDS,
package/dist/data.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ export * from './dataTypes';
2
+ export { DATA_IDENTIFIER_PATTERN, DATA_SYSTEM_COLUMNS, DATA_HIDDEN_COLUMNS, identifierIssue, isValidIdentifier } from './dataIdentifiers';
3
+ export { createTableSql, columnDefinitionSql, desiredIndexes, desiredTriggers, ftsCreateSql, ftsTableName, searchableColumns, sqlLiteral } from './dataDdl';
4
+ export { chunkRows, rowsPerInsert, ftsMatch, keysetCondition, encodeCursor, decodeCursor, isSensitiveWrite, tidyArgs, zoned } from './dataCompiler';
5
+ export type { SqlValue, KeysetCursor, SortKey } from './dataCompiler';
6
+ export { INTERNAL_MIGRATIONS, INTERNAL_SCHEMA_VERSION, hasInternalTables, getMeta, setMeta, migrateInternal, loadSchema, toTableInput, normaliseColumn, translateSqliteError, describe, query, write, rowHistory, pruneHistory, deleteImpact, createTable, updateTable, dropTable, addColumn, updateColumn, dropColumn, columnChangeNeedsRebuild, dropColumnNeedsRebuild, readTableCopy, clearFailedTableCopy, copyTableStep, writeReachesCopy, assertActor, assertWritable, exportRows } from './dataEngine';
7
+ export type { SqlRow, SqlRunner } from './dataEngine';
8
+ export type { ProjectDatabaseRpc, DatabaseInfo, ExportFile, ExportFormat, ExportState, RestoreResult } from './dataRpc';
9
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"AAEA,cAAc,aAAa,CAAC;AAC5B,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACX,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,SAAS,EACT,aAAa,EACb,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,QAAQ,EACR,KAAK,EACN,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,OAAO,EACP,OAAO,EACP,eAAe,EACf,UAAU,EACV,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,QAAQ,EACR,KAAK,EACL,KAAK,EACL,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,WAAW,EACX,SAAS,EACT,SAAS,EACT,YAAY,EACZ,UAAU,EACV,wBAAwB,EACxB,sBAAsB,EACtB,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,UAAU,EACX,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtD,YAAY,EACV,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,aAAa,EACd,MAAM,WAAW,CAAC"}
package/dist/data.js ADDED
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.writeReachesCopy = exports.copyTableStep = exports.clearFailedTableCopy = exports.readTableCopy = exports.dropColumnNeedsRebuild = exports.columnChangeNeedsRebuild = exports.dropColumn = exports.updateColumn = exports.addColumn = exports.dropTable = exports.updateTable = exports.createTable = exports.deleteImpact = exports.pruneHistory = exports.rowHistory = exports.write = exports.query = exports.describe = exports.translateSqliteError = exports.normaliseColumn = exports.toTableInput = exports.loadSchema = exports.migrateInternal = exports.setMeta = exports.getMeta = exports.hasInternalTables = exports.INTERNAL_SCHEMA_VERSION = exports.INTERNAL_MIGRATIONS = exports.zoned = exports.tidyArgs = exports.isSensitiveWrite = exports.decodeCursor = exports.encodeCursor = exports.keysetCondition = exports.ftsMatch = exports.rowsPerInsert = exports.chunkRows = exports.sqlLiteral = exports.searchableColumns = exports.ftsTableName = exports.ftsCreateSql = exports.desiredTriggers = exports.desiredIndexes = exports.columnDefinitionSql = exports.createTableSql = exports.isValidIdentifier = exports.identifierIssue = exports.DATA_HIDDEN_COLUMNS = exports.DATA_SYSTEM_COLUMNS = exports.DATA_IDENTIFIER_PATTERN = void 0;
18
+ exports.exportRows = exports.assertWritable = exports.assertActor = void 0;
19
+ // Entry point for `@ganju/utils/data`: everything a project's database and
20
+ // its callers share, without pulling in the rest of the package.
21
+ __exportStar(require("./dataTypes"), exports);
22
+ var dataIdentifiers_1 = require("./dataIdentifiers");
23
+ Object.defineProperty(exports, "DATA_IDENTIFIER_PATTERN", { enumerable: true, get: function () { return dataIdentifiers_1.DATA_IDENTIFIER_PATTERN; } });
24
+ Object.defineProperty(exports, "DATA_SYSTEM_COLUMNS", { enumerable: true, get: function () { return dataIdentifiers_1.DATA_SYSTEM_COLUMNS; } });
25
+ Object.defineProperty(exports, "DATA_HIDDEN_COLUMNS", { enumerable: true, get: function () { return dataIdentifiers_1.DATA_HIDDEN_COLUMNS; } });
26
+ Object.defineProperty(exports, "identifierIssue", { enumerable: true, get: function () { return dataIdentifiers_1.identifierIssue; } });
27
+ Object.defineProperty(exports, "isValidIdentifier", { enumerable: true, get: function () { return dataIdentifiers_1.isValidIdentifier; } });
28
+ var dataDdl_1 = require("./dataDdl");
29
+ Object.defineProperty(exports, "createTableSql", { enumerable: true, get: function () { return dataDdl_1.createTableSql; } });
30
+ Object.defineProperty(exports, "columnDefinitionSql", { enumerable: true, get: function () { return dataDdl_1.columnDefinitionSql; } });
31
+ Object.defineProperty(exports, "desiredIndexes", { enumerable: true, get: function () { return dataDdl_1.desiredIndexes; } });
32
+ Object.defineProperty(exports, "desiredTriggers", { enumerable: true, get: function () { return dataDdl_1.desiredTriggers; } });
33
+ Object.defineProperty(exports, "ftsCreateSql", { enumerable: true, get: function () { return dataDdl_1.ftsCreateSql; } });
34
+ Object.defineProperty(exports, "ftsTableName", { enumerable: true, get: function () { return dataDdl_1.ftsTableName; } });
35
+ Object.defineProperty(exports, "searchableColumns", { enumerable: true, get: function () { return dataDdl_1.searchableColumns; } });
36
+ Object.defineProperty(exports, "sqlLiteral", { enumerable: true, get: function () { return dataDdl_1.sqlLiteral; } });
37
+ var dataCompiler_1 = require("./dataCompiler");
38
+ Object.defineProperty(exports, "chunkRows", { enumerable: true, get: function () { return dataCompiler_1.chunkRows; } });
39
+ Object.defineProperty(exports, "rowsPerInsert", { enumerable: true, get: function () { return dataCompiler_1.rowsPerInsert; } });
40
+ Object.defineProperty(exports, "ftsMatch", { enumerable: true, get: function () { return dataCompiler_1.ftsMatch; } });
41
+ Object.defineProperty(exports, "keysetCondition", { enumerable: true, get: function () { return dataCompiler_1.keysetCondition; } });
42
+ Object.defineProperty(exports, "encodeCursor", { enumerable: true, get: function () { return dataCompiler_1.encodeCursor; } });
43
+ Object.defineProperty(exports, "decodeCursor", { enumerable: true, get: function () { return dataCompiler_1.decodeCursor; } });
44
+ Object.defineProperty(exports, "isSensitiveWrite", { enumerable: true, get: function () { return dataCompiler_1.isSensitiveWrite; } });
45
+ Object.defineProperty(exports, "tidyArgs", { enumerable: true, get: function () { return dataCompiler_1.tidyArgs; } });
46
+ Object.defineProperty(exports, "zoned", { enumerable: true, get: function () { return dataCompiler_1.zoned; } });
47
+ var dataEngine_1 = require("./dataEngine");
48
+ Object.defineProperty(exports, "INTERNAL_MIGRATIONS", { enumerable: true, get: function () { return dataEngine_1.INTERNAL_MIGRATIONS; } });
49
+ Object.defineProperty(exports, "INTERNAL_SCHEMA_VERSION", { enumerable: true, get: function () { return dataEngine_1.INTERNAL_SCHEMA_VERSION; } });
50
+ Object.defineProperty(exports, "hasInternalTables", { enumerable: true, get: function () { return dataEngine_1.hasInternalTables; } });
51
+ Object.defineProperty(exports, "getMeta", { enumerable: true, get: function () { return dataEngine_1.getMeta; } });
52
+ Object.defineProperty(exports, "setMeta", { enumerable: true, get: function () { return dataEngine_1.setMeta; } });
53
+ Object.defineProperty(exports, "migrateInternal", { enumerable: true, get: function () { return dataEngine_1.migrateInternal; } });
54
+ Object.defineProperty(exports, "loadSchema", { enumerable: true, get: function () { return dataEngine_1.loadSchema; } });
55
+ Object.defineProperty(exports, "toTableInput", { enumerable: true, get: function () { return dataEngine_1.toTableInput; } });
56
+ Object.defineProperty(exports, "normaliseColumn", { enumerable: true, get: function () { return dataEngine_1.normaliseColumn; } });
57
+ Object.defineProperty(exports, "translateSqliteError", { enumerable: true, get: function () { return dataEngine_1.translateSqliteError; } });
58
+ Object.defineProperty(exports, "describe", { enumerable: true, get: function () { return dataEngine_1.describe; } });
59
+ Object.defineProperty(exports, "query", { enumerable: true, get: function () { return dataEngine_1.query; } });
60
+ Object.defineProperty(exports, "write", { enumerable: true, get: function () { return dataEngine_1.write; } });
61
+ Object.defineProperty(exports, "rowHistory", { enumerable: true, get: function () { return dataEngine_1.rowHistory; } });
62
+ Object.defineProperty(exports, "pruneHistory", { enumerable: true, get: function () { return dataEngine_1.pruneHistory; } });
63
+ Object.defineProperty(exports, "deleteImpact", { enumerable: true, get: function () { return dataEngine_1.deleteImpact; } });
64
+ Object.defineProperty(exports, "createTable", { enumerable: true, get: function () { return dataEngine_1.createTable; } });
65
+ Object.defineProperty(exports, "updateTable", { enumerable: true, get: function () { return dataEngine_1.updateTable; } });
66
+ Object.defineProperty(exports, "dropTable", { enumerable: true, get: function () { return dataEngine_1.dropTable; } });
67
+ Object.defineProperty(exports, "addColumn", { enumerable: true, get: function () { return dataEngine_1.addColumn; } });
68
+ Object.defineProperty(exports, "updateColumn", { enumerable: true, get: function () { return dataEngine_1.updateColumn; } });
69
+ Object.defineProperty(exports, "dropColumn", { enumerable: true, get: function () { return dataEngine_1.dropColumn; } });
70
+ Object.defineProperty(exports, "columnChangeNeedsRebuild", { enumerable: true, get: function () { return dataEngine_1.columnChangeNeedsRebuild; } });
71
+ Object.defineProperty(exports, "dropColumnNeedsRebuild", { enumerable: true, get: function () { return dataEngine_1.dropColumnNeedsRebuild; } });
72
+ Object.defineProperty(exports, "readTableCopy", { enumerable: true, get: function () { return dataEngine_1.readTableCopy; } });
73
+ Object.defineProperty(exports, "clearFailedTableCopy", { enumerable: true, get: function () { return dataEngine_1.clearFailedTableCopy; } });
74
+ Object.defineProperty(exports, "copyTableStep", { enumerable: true, get: function () { return dataEngine_1.copyTableStep; } });
75
+ Object.defineProperty(exports, "writeReachesCopy", { enumerable: true, get: function () { return dataEngine_1.writeReachesCopy; } });
76
+ Object.defineProperty(exports, "assertActor", { enumerable: true, get: function () { return dataEngine_1.assertActor; } });
77
+ Object.defineProperty(exports, "assertWritable", { enumerable: true, get: function () { return dataEngine_1.assertWritable; } });
78
+ Object.defineProperty(exports, "exportRows", { enumerable: true, get: function () { return dataEngine_1.exportRows; } });