thinkwork-cli 0.13.1 → 1.0.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.
- package/README.md +3 -14
- package/dist/{api-client-4DZ266J5.js → api-client-4P4JZOBX.js} +3 -1
- package/dist/bowser-6Z6JFAIR.js +2822 -0
- package/dist/{chunk-Y2WHJECR.js → chunk-4OMDWYZQ.js} +5 -44
- package/dist/chunk-AD2NIWB5.js +6516 -0
- package/dist/chunk-DV3MRBR5.js +43 -0
- package/dist/chunk-EI5ZX7CN.js +522 -0
- package/dist/chunk-EUJ7X6YD.js +126 -0
- package/dist/chunk-GG5WKBOX.js +436 -0
- package/dist/chunk-I64EZSU5.js +358 -0
- package/dist/chunk-KMIJ5KGT.js +128 -0
- package/dist/chunk-MWQ7RO76.js +137 -0
- package/dist/chunk-OCPHU34C.js +996 -0
- package/dist/chunk-OLUQ4U2Z.js +1728 -0
- package/dist/chunk-XYM7PE2A.js +2264 -0
- package/dist/chunk-YQCYD6NE.js +3299 -0
- package/dist/cli.js +49156 -31257
- package/dist/commands/enterprise/templates/deploy-repo/scripts/apply-release.mjs +0 -1
- package/dist/commands/enterprise/templates/deploy-repo/scripts/smoke.mjs +0 -1
- package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +0 -14
- package/dist/dist-es-2OTNTL4N.js +315 -0
- package/dist/dist-es-2XVAH4BQ.js +14726 -0
- package/dist/dist-es-3DPDUJAH.js +2000 -0
- package/dist/dist-es-BNZTBBVC.js +176 -0
- package/dist/dist-es-CD2RBDAC.js +88 -0
- package/dist/dist-es-I4FW57PS.js +88 -0
- package/dist/dist-es-KL7Y5NB2.js +377 -0
- package/dist/dist-es-KVFWJNDY.js +318 -0
- package/dist/dist-es-PS73DWNL.js +70 -0
- package/dist/dist-es-S3NZQFGT.js +170 -0
- package/dist/dist-es-SGCA4P32.js +48 -0
- package/dist/dist-es-WBM6J4RA.js +70 -0
- package/dist/dist-es-ZGVADYIF.js +485 -0
- package/dist/dist-es-ZKC2QKD2.js +377 -0
- package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +2 -1
- package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +1 -0
- package/dist/drizzle/0090_brain_schema_extraction.sql +10 -0
- package/dist/drizzle/0132_drop_computer_tables.sql +3 -0
- package/dist/drizzle/0160_compliance_event_types_plugins.sql +2 -0
- package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +1 -0
- package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +1 -0
- package/dist/drizzle/0227_analyst_reader_role.sql +17 -20
- package/dist/drizzle/0230_analyst_rls.sql +28 -36
- package/dist/drizzle/0250_kg_schema_extraction.sql +27 -0
- package/dist/drizzle/0251_brain_stragglers.sql +21 -0
- package/dist/drizzle/0253_drop_brain_substrate.sql +2 -0
- package/dist/drizzle/0257_agents_runtime_allow_harness.sql +24 -0
- package/dist/drizzle/0261_native_auth_control_plane.sql +332 -0
- package/dist/drizzle/0262_auth_subscription_tickets.sql +59 -0
- package/dist/drizzle/0263_agentcore_runtime_identifier.sql +69 -0
- package/dist/drizzle/0263_drop_workos_auth_runtime.sql +236 -0
- package/dist/drizzle/0264_auth_enrollment_attempt_limits.sql +15 -0
- package/dist/drizzle/0265_eval_runs_requester_identity.sql +28 -0
- package/dist/drizzle/0265_require_fully_valid_auth_publication.sql +27 -0
- package/dist/drizzle/0266_auth_identity_recovery_grants.sql +9 -0
- package/dist/drizzle/0266_eval_profiles_runtime_type.sql +12 -0
- package/dist/drizzle/0267_ontology_candidate_rejections.sql +53 -0
- package/dist/drizzle/0268_identity_crosswalk_routing.sql +182 -0
- package/dist/drizzle/0269_ontology_system_map.sql +31 -0
- package/dist/drizzle/0270_tool_execution_ledger.sql +115 -0
- package/dist/drizzle/0271_ontology_twin_declarations.sql +47 -0
- package/dist/drizzle/0272_identity_graph_projection_cursor.sql +23 -0
- package/dist/drizzle/0273_twin_materialization_suggestions.sql +29 -0
- package/dist/drizzle/0274_tenant_mcp_twin_keys.sql +59 -0
- package/dist/drizzle/0275_identity_bulk_rebuild_fence.sql +30 -0
- package/dist/drizzle/0276_tool_execution_ledger_allow_cascade_delete.sql +18 -0
- package/dist/drizzle/0277_knowledge_base_sources.sql +107 -0
- package/dist/drizzle/0278_kb_page_transcription.sql +55 -0
- package/dist/drizzle/0279_mcp_servers_off_plugin_provenance.sql +93 -0
- package/dist/drizzle/0280_work_item_external_refs_drop_plane_provider.sql +46 -0
- package/dist/drizzle/0281_tenant_mcp_twin_keys_expiry_suffix.sql +9 -0
- package/dist/drizzle/0282_tenant_mcp_twin_keys_grants.sql +24 -0
- package/dist/drizzle/0283_agents_agentcore_runtime_dispatch.sql +13 -0
- package/dist/drizzle/0284_user_brain_claims.sql +69 -0
- package/dist/drizzle/0285_tenant_mcp_twin_keys_trusted_subsystem.sql +30 -0
- package/dist/drizzle/0286_brain_analytics_key.sql +26 -0
- package/dist/drizzle/0287_brain_subject.sql +25 -0
- package/dist/drizzle/0288_multi_lane_identities.sql +25 -0
- package/dist/event-streams-7JNLJEEL.js +894 -0
- package/dist/event-streams-KDF5RWR6.js +1515 -0
- package/dist/loadSso-ETCXTR4I.js +576 -0
- package/dist/loadSso-UBD7KUHE.js +583 -0
- package/dist/plugins/README.md +2 -2
- package/dist/plugins/catalog/package.json +1 -5
- package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +6 -4
- package/dist/plugins/catalog/src/__tests__/catalog.test.ts +21 -21
- package/dist/plugins/catalog/src/__tests__/contracts.test.ts +102 -94
- package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +7 -8
- package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -20
- package/dist/plugins/catalog/src/contracts.ts +17 -179
- package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -24
- package/dist/plugins/n8n/test/integrated-app-contract.test.ts +1 -1
- package/dist/plugins/twenty/package.json +2 -1
- package/dist/plugins/twenty/scripts/LAMBDA_DEPLOY.md +114 -0
- package/dist/plugins/twenty/scripts/build-lambda.sh +29 -0
- package/dist/plugins/twenty/scripts/configure-product-views.ts +195 -0
- package/dist/plugins/twenty/scripts/lambda-handler.ts +49 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/load-attachments.test.ts +38 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +145 -2
- package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +397 -151
- package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +28 -129
- package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +10 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +13 -8
- package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +222 -2
- package/dist/plugins/twenty/scripts/lib/load-attachments.ts +29 -0
- package/dist/plugins/twenty/scripts/lib/load-records.ts +160 -43
- package/dist/plugins/twenty/scripts/lib/mappers.ts +368 -152
- package/dist/plugins/twenty/scripts/lib/members-ensure.ts +43 -268
- package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +57 -0
- package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +136 -31
- package/dist/plugins/twenty/scripts/migrate-lastmile.ts +254 -152
- package/dist/plugins/twenty/scripts/provision-twenty-members.ts +44 -1
- package/dist/plugins/twenty/scripts/purge-lastmile-import.ts +178 -0
- package/dist/plugins/twenty/scripts/restructure-products.ts +312 -0
- package/dist/plugins/twenty/scripts/retag-stage-values.ts +362 -0
- package/dist/plugins/twenty/test/manifest.test.ts +2 -4
- package/dist/scripts/post-deploy.sh +79 -1
- package/dist/signin-5QZNRSOO.js +821 -0
- package/dist/sso-oidc-XK673P54.js +837 -0
- package/dist/sts-OXI2UALF.js +1113 -0
- package/dist/sts-SQW4NBK3.js +1117 -0
- package/dist/terraform/examples/greenfield/main.tf +391 -176
- package/dist/terraform/examples/greenfield/terraform.tfvars.example +26 -8
- package/dist/terraform/modules/app/agentcore-admin/main.tf +47 -0
- package/dist/terraform/modules/app/agentcore-code-interpreter/README.md +39 -47
- package/dist/terraform/modules/app/agentcore-code-interpreter/main.tf +13 -66
- package/dist/terraform/modules/app/agentcore-identity/main.tf +253 -0
- package/dist/terraform/modules/app/agentcore-identity/outputs.tf +51 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +239 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +22 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/delete_twenty_identity.sh +16 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/delete_workload_identity.sh +19 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/ensure_workload_identity.sh +29 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/read_identity.sh +55 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_identity.sh +73 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +45 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +123 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/after.tf +15 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/before.tf +7 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-after.tf +8 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-before.tf +9 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-after.tf +3 -0
- package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-before.tf +3 -0
- package/dist/terraform/modules/app/agentcore-identity/variables.tf +60 -0
- package/dist/terraform/modules/app/agentcore-memory/README.md +46 -9
- package/dist/terraform/modules/app/agentcore-memory/main.tf +27 -10
- package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +156 -24
- package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
- package/dist/terraform/modules/app/agentcore-pi/main.tf +42 -52
- package/dist/terraform/modules/app/agentcore-pi/outputs.tf +3 -3
- package/dist/terraform/modules/app/agentcore-pi/scripts/reconcile_pi_runtime.mjs +175 -0
- package/dist/terraform/modules/app/agentcore-pi/variables.tf +35 -28
- package/dist/terraform/modules/app/agentcore-platform/main.tf +68 -0
- package/dist/terraform/modules/app/agentcore-runtime/main.tf +4 -20
- package/dist/terraform/modules/app/appsync-subscriptions/main.tf +127 -21
- package/dist/terraform/modules/app/appsync-subscriptions/outputs.tf +0 -6
- package/dist/terraform/modules/app/appsync-subscriptions/variables.tf +5 -0
- package/dist/terraform/modules/app/capability-broker/main.tf +2 -2
- package/dist/terraform/modules/app/capability-broker/variables.tf +11 -0
- package/dist/terraform/modules/app/deployment-control-plane/README.md +264 -0
- package/dist/terraform/modules/app/deployment-control-plane/buildspec.yml +4 -1
- package/dist/terraform/modules/app/deployment-control-plane/main.tf +94 -0
- package/dist/terraform/modules/app/deployment-control-plane/outputs.tf +5 -0
- package/dist/terraform/modules/app/deployment-control-plane/runner.py +3689 -233
- package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +2579 -140
- package/dist/terraform/modules/app/deployment-control-plane/variables.tf +33 -0
- package/dist/terraform/modules/app/lambda-api/auth-state.tf +72 -0
- package/dist/terraform/modules/app/lambda-api/chat-latency-observability.tf +466 -0
- package/dist/terraform/modules/app/lambda-api/dispatch-dlq.tf +55 -0
- package/dist/terraform/modules/app/lambda-api/handlers.tf +531 -619
- package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +350 -241
- package/dist/terraform/modules/app/lambda-api/main.tf +75 -13
- package/dist/terraform/modules/app/lambda-api/memory-alarms.tf +3 -28
- package/dist/terraform/modules/app/lambda-api/oauth-secrets.tf +1 -2
- package/dist/terraform/modules/app/lambda-api/outputs.tf +17 -10
- package/dist/terraform/modules/app/lambda-api/runtime-config.tf +3 -21
- package/dist/terraform/modules/app/lambda-api/turn-assertion.tf +45 -0
- package/dist/terraform/modules/app/lambda-api/variables.tf +307 -121
- package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/README.md +1 -1
- package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/main.tf +18 -18
- package/dist/terraform/modules/app/sandbox-log-scrubber/README.md +11 -10
- package/dist/terraform/modules/app/sandbox-log-scrubber/main.tf +5 -5
- package/dist/terraform/modules/app/static-site/main.tf +1 -1
- package/dist/terraform/modules/app/www-dns/main.tf +9 -27
- package/dist/terraform/modules/app/www-dns/variables.tf +4 -10
- package/dist/terraform/modules/data/aurora-postgres/README.md +34 -0
- package/dist/terraform/modules/data/aurora-postgres/alarms.tf +82 -0
- package/dist/terraform/modules/data/aurora-postgres/main.tf +27 -57
- package/dist/terraform/modules/data/aurora-postgres/outputs.tf +0 -9
- package/dist/terraform/modules/data/aurora-postgres/variables.tf +41 -0
- package/dist/terraform/modules/data/s3-buckets/main.tf +5 -6
- package/dist/terraform/modules/foundation/cognito/main.tf +367 -72
- package/dist/terraform/modules/foundation/cognito/outputs.tf +47 -0
- package/dist/terraform/modules/foundation/cognito/variables.tf +131 -9
- package/dist/terraform/modules/thinkwork/README.md +5 -1
- package/dist/terraform/modules/thinkwork/main.tf +459 -234
- package/dist/terraform/modules/thinkwork/outputs.tf +44 -62
- package/dist/terraform/modules/thinkwork/variables.tf +353 -89
- package/dist/terraform/schema.graphql +69 -36
- package/dist/workspace-defaults/files/INSTRUCTIONS.md +9 -11
- package/dist/workspace-defaults/files/MEMORY_GUIDE.md +38 -35
- package/dist/workspace-defaults/files/ROUTER.md +1 -1
- package/dist/workspace-defaults/files/TOOLS.md +9 -39
- package/dist/workspace-defaults/files/USER.md +1 -0
- package/dist/workspace-defaults/files/agents/analyst/INSTRUCTIONS.md +6 -3
- package/dist/workspace-defaults/files/catalog-skills/brain-brief-builder/SKILL.md +165 -0
- package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/SKILL.md +75 -0
- package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/mcp-tooling.md +40 -0
- package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/validation-and-handoff.md +40 -0
- package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/workflow-authoring.md +46 -0
- package/dist/workspace-defaults/files/skills/artifact-builder/references/crm-dashboard.md +1 -1
- package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +22 -3
- package/package.json +3 -2
- package/dist/drizzle/0261_thread_turns_origin_turn_index.sql +0 -11
- package/dist/plugins/company-data/README.md +0 -49
- package/dist/plugins/company-data/package.json +0 -21
- package/dist/plugins/company-data/src/index.ts +0 -30
- package/dist/plugins/company-data/src/manifest.ts +0 -26
- package/dist/plugins/company-data/test/manifest.test.ts +0 -116
- package/dist/plugins/company-data/tsconfig.json +0 -8
- package/dist/plugins/company-etl/README.md +0 -46
- package/dist/plugins/company-etl/package.json +0 -21
- package/dist/plugins/company-etl/src/index.ts +0 -29
- package/dist/plugins/company-etl/src/manifest.ts +0 -26
- package/dist/plugins/company-etl/test/manifest.test.ts +0 -108
- package/dist/plugins/company-etl/tsconfig.json +0 -8
- package/dist/plugins/lastmile/README.md +0 -50
- package/dist/plugins/lastmile/package.json +0 -23
- package/dist/plugins/lastmile/smoke/lastmile-plugin-smoke.mjs +0 -661
- package/dist/plugins/lastmile/src/api/tasks-adapter.ts +0 -572
- package/dist/plugins/lastmile/src/discovery.fixture.ts +0 -64
- package/dist/plugins/lastmile/src/index.ts +0 -46
- package/dist/plugins/lastmile/src/manifest.ts +0 -139
- package/dist/plugins/lastmile/test/api/tasks-adapter.test.ts +0 -266
- package/dist/plugins/lastmile/test/discovery.test.ts +0 -88
- package/dist/plugins/lastmile/tsconfig.json +0 -8
- package/dist/plugins/n8n/smoke/n8n-managed-app-smoke.mjs +0 -409
- package/dist/plugins/twenty/smoke/twenty-managed-app-smoke.mjs +0 -359
- package/dist/plugins/workos-auth/package.json +0 -22
- package/dist/plugins/workos-auth/src/index.ts +0 -30
- package/dist/plugins/workos-auth/src/manifest.ts +0 -40
- package/dist/plugins/workos-auth/src/provider-contract.ts +0 -39
- package/dist/plugins/workos-auth/test/manifest.test.ts +0 -94
- package/dist/plugins/workos-auth/tsconfig.json +0 -8
- package/dist/terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base +0 -61
- package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py +0 -227
- package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/test_sitecustomize.py +0 -277
- package/dist/terraform/modules/app/agentcore-code-interpreter/scripts/build_and_push_sandbox_base.sh +0 -70
- package/dist/terraform/modules/app/agentcore-harness/main.tf +0 -101
- package/dist/terraform/modules/app/agentcore-harness/outputs.tf +0 -9
- package/dist/terraform/modules/app/agentcore-harness/variables.tf +0 -25
- package/dist/terraform/modules/app/hindsight-memory/README.md +0 -89
- package/dist/terraform/modules/app/hindsight-memory/main.tf +0 -411
- package/dist/terraform/modules/data/bedrock-knowledge-base/main.tf +0 -102
- /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/outputs.tf +0 -0
- /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/sync-database.py +0 -0
- /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/test_sync_database.py +0 -0
- /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/variables.tf +0 -0
- /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/README.md +0 -0
- /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/main.tf +0 -0
- /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/outputs.tf +0 -0
- /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/variables.tf +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Lambda entry point for the nightly LastMile → Twenty sync.
|
|
3
|
+
*
|
|
4
|
+
* Invoked by n8n (Schedule → AWS Lambda) in TEI's account, where the function
|
|
5
|
+
* can reach both the LastMile RDS and crm.tei.thinkwork.ai. Reads the same
|
|
6
|
+
* three env vars as the CLI and runs an APPLY (delta re-sync) by default; pass
|
|
7
|
+
* `{"mode":"dry-run"}` to read + report without writing. Returns the parity
|
|
8
|
+
* report so n8n can log it or branch on failures.
|
|
9
|
+
*
|
|
10
|
+
* The sync is idempotent (upsert by sourceId + deletion mirror), reads LastMile
|
|
11
|
+
* read-only, never provisions members, and needs no AWS credentials. Runtime is
|
|
12
|
+
* ~90s against TEI's current data — set the Lambda timeout to 300s for headroom.
|
|
13
|
+
*
|
|
14
|
+
* Build the deployment zip with scripts/build-lambda.sh; deploy per
|
|
15
|
+
* scripts/LAMBDA_DEPLOY.md. Handler string: `index.handler`.
|
|
16
|
+
*/
|
|
17
|
+
import { executeMigration } from "./migrate-lastmile";
|
|
18
|
+
|
|
19
|
+
interface SyncEvent {
|
|
20
|
+
mode?: "apply" | "dry-run";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface EntityFailures {
|
|
24
|
+
failed?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function totalFailed(report: Record<string, unknown>): number {
|
|
28
|
+
let failed = 0;
|
|
29
|
+
for (const value of Object.values(report)) {
|
|
30
|
+
if (value && typeof value === "object" && "failed" in value) {
|
|
31
|
+
const n = (value as EntityFailures).failed;
|
|
32
|
+
if (typeof n === "number") failed += n;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return failed;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function handler(
|
|
39
|
+
event: SyncEvent | null,
|
|
40
|
+
): Promise<{ ok: boolean; failed: number; report: Record<string, unknown> }> {
|
|
41
|
+
// Default to apply — the whole point of the scheduled invocation. A hard
|
|
42
|
+
// failure (DB unreachable, sourceId abort) throws and fails the invocation;
|
|
43
|
+
// per-record soft failures surface via `failed` so n8n can alert without the
|
|
44
|
+
// run being considered a crash.
|
|
45
|
+
const apply = event?.mode !== "dry-run";
|
|
46
|
+
const report = await executeMigration({ apply });
|
|
47
|
+
const failed = totalFailed(report);
|
|
48
|
+
return { ok: failed === 0, failed, report };
|
|
49
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { isUploadUnsupported } from "../load-attachments";
|
|
4
|
+
import { TwentyGraphqlError } from "../twenty-client";
|
|
5
|
+
|
|
6
|
+
describe("isUploadUnsupported", () => {
|
|
7
|
+
it("recognizes the missing Upload scalar and uploadFile mutation", () => {
|
|
8
|
+
expect(
|
|
9
|
+
isUploadUnsupported(
|
|
10
|
+
new TwentyGraphqlError("x", {
|
|
11
|
+
errors: [{ message: 'Unknown type "Upload". Did you mean "Float"?' }],
|
|
12
|
+
}),
|
|
13
|
+
),
|
|
14
|
+
).toBe(true);
|
|
15
|
+
expect(
|
|
16
|
+
isUploadUnsupported(
|
|
17
|
+
new TwentyGraphqlError("x", {
|
|
18
|
+
errors: [
|
|
19
|
+
{ message: 'Cannot query field "uploadFile" on type "Mutation".' },
|
|
20
|
+
],
|
|
21
|
+
}),
|
|
22
|
+
),
|
|
23
|
+
).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("does not swallow a genuine upload failure", () => {
|
|
27
|
+
// A real 500 or a missing binary must still count as a failure, so the run
|
|
28
|
+
// exits non-zero and someone looks at it.
|
|
29
|
+
expect(
|
|
30
|
+
isUploadUnsupported(
|
|
31
|
+
new TwentyGraphqlError("x", {
|
|
32
|
+
errors: [{ message: "Internal server error" }],
|
|
33
|
+
}),
|
|
34
|
+
),
|
|
35
|
+
).toBe(false);
|
|
36
|
+
expect(isUploadUnsupported(new Error("connect ETIMEDOUT"))).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -3,12 +3,14 @@ import { describe, expect, it, vi } from "vitest";
|
|
|
3
3
|
import {
|
|
4
4
|
COMPANY,
|
|
5
5
|
emptyCounters,
|
|
6
|
+
isMissingSourceIdFieldError,
|
|
6
7
|
mirrorDeletions,
|
|
8
|
+
upsertNotes,
|
|
7
9
|
upsertRecords,
|
|
8
10
|
} from "../load-records";
|
|
9
11
|
import { contentHash } from "../mappers";
|
|
10
|
-
import type { MappedRecord } from "../mappers";
|
|
11
|
-
import type
|
|
12
|
+
import type { MappedNote, MappedRecord } from "../mappers";
|
|
13
|
+
import { TwentyGraphqlError, type TwentyClient } from "../twenty-client";
|
|
12
14
|
|
|
13
15
|
function mapped(
|
|
14
16
|
sourceId: string,
|
|
@@ -230,3 +232,144 @@ describe("mirrorDeletions (AE2 / KTD7)", () => {
|
|
|
230
232
|
]);
|
|
231
233
|
});
|
|
232
234
|
});
|
|
235
|
+
|
|
236
|
+
describe("isMissingSourceIdFieldError", () => {
|
|
237
|
+
const gqlError = (message: string) =>
|
|
238
|
+
new TwentyGraphqlError("wrapped", { errors: [{ message }] });
|
|
239
|
+
|
|
240
|
+
it("recognizes a not-yet-created sourceId field", () => {
|
|
241
|
+
expect(
|
|
242
|
+
isMissingSourceIdFieldError(
|
|
243
|
+
gqlError('Object company doesn\'t have any "sourceId" field.'),
|
|
244
|
+
),
|
|
245
|
+
).toBe(true);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("recognizes a not-yet-created custom object", () => {
|
|
249
|
+
expect(
|
|
250
|
+
isMissingSourceIdFieldError(
|
|
251
|
+
gqlError('Unknown type "OrganizationFilterInput".'),
|
|
252
|
+
),
|
|
253
|
+
).toBe(true);
|
|
254
|
+
expect(
|
|
255
|
+
isMissingSourceIdFieldError(
|
|
256
|
+
gqlError('Cannot query field "organizations" on type "Query".'),
|
|
257
|
+
),
|
|
258
|
+
).toBe(true);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("does not swallow unrelated errors", () => {
|
|
262
|
+
expect(isMissingSourceIdFieldError(gqlError("Rate limit reached"))).toBe(
|
|
263
|
+
false,
|
|
264
|
+
);
|
|
265
|
+
expect(isMissingSourceIdFieldError(new Error("boom"))).toBe(false);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe("upsertNotes batches the NoteTarget existence check (perf)", () => {
|
|
270
|
+
function note(sourceId: string): MappedNote {
|
|
271
|
+
return {
|
|
272
|
+
sourceId,
|
|
273
|
+
title: sourceId,
|
|
274
|
+
bodyMarkdown: sourceId,
|
|
275
|
+
targetSourceId: "opportunity:o1",
|
|
276
|
+
targetKind: "opportunity",
|
|
277
|
+
isDeleted: false,
|
|
278
|
+
createdAt: null,
|
|
279
|
+
authorName: null,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// A note whose id appears here already has a NoteTarget in Twenty.
|
|
284
|
+
function noteClient(pairedNoteIds: string[]): {
|
|
285
|
+
client: TwentyClient;
|
|
286
|
+
lookups: number;
|
|
287
|
+
createdTargets: Array<Record<string, unknown>>;
|
|
288
|
+
} {
|
|
289
|
+
const state = {
|
|
290
|
+
lookups: 0,
|
|
291
|
+
createdTargets: [] as Record<string, unknown>[],
|
|
292
|
+
};
|
|
293
|
+
const client = {
|
|
294
|
+
requestWithRetry: vi.fn(
|
|
295
|
+
async (
|
|
296
|
+
_path: string,
|
|
297
|
+
query: string,
|
|
298
|
+
variables: { filter?: { noteId?: { in?: string[] } } },
|
|
299
|
+
) => {
|
|
300
|
+
if (query.includes("MigrationNoteTargets")) {
|
|
301
|
+
state.lookups += 1;
|
|
302
|
+
const ids = variables.filter?.noteId?.in ?? [];
|
|
303
|
+
return {
|
|
304
|
+
noteTargets: {
|
|
305
|
+
edges: ids
|
|
306
|
+
.filter((id) => pairedNoteIds.includes(id))
|
|
307
|
+
.map((id) => ({ node: { noteId: id } })),
|
|
308
|
+
pageInfo: { hasNextPage: false, endCursor: null },
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
// Note sourceId existence lookups → nothing exists yet (force create).
|
|
313
|
+
return { notes: { edges: [] } };
|
|
314
|
+
},
|
|
315
|
+
),
|
|
316
|
+
requestOnce: vi.fn(
|
|
317
|
+
async (
|
|
318
|
+
_path: string,
|
|
319
|
+
query: string,
|
|
320
|
+
variables: { data: Array<Record<string, unknown>> },
|
|
321
|
+
) => {
|
|
322
|
+
if (query.includes("createNotes")) {
|
|
323
|
+
return {
|
|
324
|
+
createNotes: variables.data.map((row) => ({
|
|
325
|
+
id: `note-${row.sourceId as string}`,
|
|
326
|
+
sourceId: row.sourceId,
|
|
327
|
+
})),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
if (query.includes("createNoteTargets")) {
|
|
331
|
+
state.createdTargets.push(...variables.data);
|
|
332
|
+
return {
|
|
333
|
+
createNoteTargets: variables.data.map((_, i) => ({
|
|
334
|
+
id: `nt-${i}`,
|
|
335
|
+
})),
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
return { ok: true };
|
|
339
|
+
},
|
|
340
|
+
),
|
|
341
|
+
} as unknown as TwentyClient;
|
|
342
|
+
return { client, ...state };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
it("issues one lookup for many notes and only creates the missing targets", async () => {
|
|
346
|
+
const notes = [note("task_comment:c1"), note("task_comment:c2")];
|
|
347
|
+
// c1 already has its target; c2 does not.
|
|
348
|
+
const harness = noteClient(["note-task_comment:c1"]);
|
|
349
|
+
const counters = emptyCounters();
|
|
350
|
+
|
|
351
|
+
await upsertNotes({
|
|
352
|
+
client: harness.client,
|
|
353
|
+
notes,
|
|
354
|
+
targetIdBySourceId: new Map([["opportunity:o1", "opp1"]]),
|
|
355
|
+
dryRun: false,
|
|
356
|
+
counters,
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// Batched: a single noteTargets query covers both notes (was one per note).
|
|
360
|
+
const lookupCalls = (
|
|
361
|
+
harness.client.requestWithRetry as unknown as {
|
|
362
|
+
mock: { calls: unknown[] };
|
|
363
|
+
}
|
|
364
|
+
).mock.calls.filter((c) =>
|
|
365
|
+
String((c as unknown[])[1]).includes("MigrationNoteTargets"),
|
|
366
|
+
).length;
|
|
367
|
+
expect(lookupCalls).toBe(1);
|
|
368
|
+
|
|
369
|
+
// Only the unpaired note gets a target, and it carries the opportunity FK.
|
|
370
|
+
expect(harness.createdTargets).toEqual([
|
|
371
|
+
{ noteId: "note-task_comment:c2", targetOpportunityId: "opp1" },
|
|
372
|
+
]);
|
|
373
|
+
expect(counters.failed).toBe(0);
|
|
374
|
+
});
|
|
375
|
+
});
|