thinkwork-cli 0.13.2 → 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-JYZXYQJR.js → api-client-4P4JZOBX.js} +1 -1
- package/dist/{chunk-Z2F6RJFR.js → chunk-4OMDWYZQ.js} +4 -5
- package/dist/{chunk-ILZKG5WV.js → chunk-AD2NIWB5.js} +434 -69
- package/dist/chunk-MWQ7RO76.js +137 -0
- package/dist/{chunk-DVPBI5HM.js → chunk-OLUQ4U2Z.js} +26 -26
- package/dist/{chunk-QOERT44A.js → chunk-YQCYD6NE.js} +57 -44
- package/dist/cli.js +4400 -16431
- 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-CRV46D5B.js → dist-es-2OTNTL4N.js} +4 -4
- package/dist/{dist-es-ENBUC3JP.js → dist-es-2XVAH4BQ.js} +2 -2
- package/dist/{dist-es-DCY4IC3Y.js → dist-es-3DPDUJAH.js} +2 -2
- package/dist/{dist-es-G7PTG75M.js → dist-es-BNZTBBVC.js} +1 -1
- package/dist/{dist-es-GKDBE7E6.js → dist-es-CD2RBDAC.js} +1 -1
- package/dist/{dist-es-R7FGL2IB.js → dist-es-I4FW57PS.js} +1 -1
- package/dist/{dist-es-USORBXZ5.js → dist-es-KVFWJNDY.js} +4 -4
- package/dist/{dist-es-HY3535OI.js → dist-es-PS73DWNL.js} +2 -2
- package/dist/{dist-es-LDE437AM.js → dist-es-S3NZQFGT.js} +1 -1
- package/dist/{dist-es-G54LBMRN.js → dist-es-SGCA4P32.js} +1 -1
- package/dist/{dist-es-Q57SZXZ7.js → dist-es-WBM6J4RA.js} +2 -2
- package/dist/{dist-es-P26FWFLT.js → dist-es-ZGVADYIF.js} +8 -8
- package/dist/drizzle/0227_analyst_reader_role.sql +17 -26
- package/dist/drizzle/0230_analyst_rls.sql +28 -45
- package/dist/drizzle/0261_native_auth_control_plane.sql +7 -3
- 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/{loadSso-DJVB7BXE.js → loadSso-ETCXTR4I.js} +2 -2
- package/dist/{loadSso-JAMNA3WY.js → loadSso-UBD7KUHE.js} +2 -2
- package/dist/plugins/README.md +2 -2
- package/dist/plugins/catalog/package.json +0 -3
- package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +6 -3
- package/dist/plugins/catalog/src/__tests__/catalog.test.ts +21 -21
- package/dist/plugins/catalog/src/__tests__/contracts.test.ts +102 -25
- package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +7 -6
- package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -15
- package/dist/plugins/catalog/src/contracts.ts +15 -0
- package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -18
- 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-UGDWTGS4.js → signin-5QZNRSOO.js} +2 -2
- package/dist/{sso-oidc-Q4VXANXY.js → sso-oidc-XK673P54.js} +2 -2
- package/dist/{sts-CWLSE3GH.js → sts-OXI2UALF.js} +6 -134
- package/dist/{sts-DNZLNVOV.js → sts-SQW4NBK3.js} +6 -134
- package/dist/terraform/examples/greenfield/main.tf +233 -175
- package/dist/terraform/examples/greenfield/terraform.tfvars.example +12 -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 +106 -26
- package/dist/terraform/modules/app/agentcore-identity/outputs.tf +6 -6
- package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +216 -99
- package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +6 -9
- 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 +22 -7
- package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +17 -46
- package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +65 -3
- 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 +6 -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/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 +2641 -124
- package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +2034 -154
- 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 +411 -723
- package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +262 -198
- package/dist/terraform/modules/app/lambda-api/main.tf +51 -13
- package/dist/terraform/modules/app/lambda-api/mcp-oauth.tf +4 -181
- 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 -45
- package/dist/terraform/modules/app/lambda-api/turn-assertion.tf +45 -0
- package/dist/terraform/modules/app/lambda-api/variables.tf +219 -126
- 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 +81 -8
- package/dist/terraform/modules/foundation/cognito/outputs.tf +5 -0
- package/dist/terraform/modules/foundation/cognito/variables.tf +24 -12
- package/dist/terraform/modules/thinkwork/README.md +5 -1
- package/dist/terraform/modules/thinkwork/main.tf +376 -374
- package/dist/terraform/modules/thinkwork/outputs.tf +12 -158
- package/dist/terraform/modules/thinkwork/variables.tf +246 -89
- 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/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 +1 -1
- package/dist/drizzle/0261_managed_harness_multiplayer.sql +0 -313
- package/dist/drizzle/0262_parallel_harness_threads.sql +0 -9
- package/dist/drizzle/0264_harness_tool_execution_ledger.sql +0 -113
- 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/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-gateway/main.tf +0 -305
- package/dist/terraform/modules/app/agentcore-gateway/outputs.tf +0 -44
- package/dist/terraform/modules/app/agentcore-gateway/scripts/delete_gateway.sh +0 -93
- package/dist/terraform/modules/app/agentcore-gateway/scripts/read_gateway.sh +0 -33
- package/dist/terraform/modules/app/agentcore-gateway/scripts/reconcile_gateway.sh +0 -543
- package/dist/terraform/modules/app/agentcore-gateway/variables.tf +0 -70
- package/dist/terraform/modules/app/agentcore-harness/main.tf +0 -330
- package/dist/terraform/modules/app/agentcore-harness/outputs.tf +0 -72
- package/dist/terraform/modules/app/agentcore-harness/scripts/delete_harness.sh +0 -5
- package/dist/terraform/modules/app/agentcore-harness/scripts/harness-lifecycle.mjs +0 -430
- package/dist/terraform/modules/app/agentcore-harness/scripts/harness-readback.mjs +0 -180
- package/dist/terraform/modules/app/agentcore-harness/scripts/harness-tool-contract.mjs +0 -193
- package/dist/terraform/modules/app/agentcore-harness/scripts/prune_harness.sh +0 -5
- package/dist/terraform/modules/app/agentcore-harness/scripts/read_harness.sh +0 -5
- package/dist/terraform/modules/app/agentcore-harness/scripts/reconcile_harness.sh +0 -5
- package/dist/terraform/modules/app/agentcore-harness/variables.tf +0 -96
- 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/app/lambda-api/agentcore-harness-alarms.tf +0 -88
- package/dist/terraform/modules/app/lambda-api/agentcore-identity-alarms.tf +0 -91
- 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
|
@@ -24,15 +24,24 @@ import {
|
|
|
24
24
|
|
|
25
25
|
const QUERY_PAGE = 200;
|
|
26
26
|
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
/**
|
|
28
|
+
* True when Twenty rejects a query because schema this run would create does
|
|
29
|
+
* not exist yet: a missing `sourceId` custom field, or a whole missing custom
|
|
30
|
+
* object (`opportunityProduct`, `organization`). A dry-run plans that schema
|
|
31
|
+
* but cannot create it, so nothing can carry a sourceId and the honest answer
|
|
32
|
+
* to "what already exists?" is "nothing".
|
|
33
|
+
*
|
|
34
|
+
* Apply runs create objects and fields before any record pass, so this can
|
|
35
|
+
* only fire in dry-run; a genuine apply-time schema gap aborts in the metadata
|
|
36
|
+
* phase, before record loading.
|
|
37
|
+
*/
|
|
30
38
|
export function isMissingSourceIdFieldError(error: unknown): boolean {
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/doesn't have any .?sourceId.? field/i.test(entry.message)
|
|
35
|
-
|
|
39
|
+
if (!(error instanceof TwentyGraphqlError)) return false;
|
|
40
|
+
return error.errors.some(
|
|
41
|
+
(entry) =>
|
|
42
|
+
/doesn't have any .?sourceId.? field/i.test(entry.message) ||
|
|
43
|
+
/Unknown type "\w+FilterInput"/i.test(entry.message) ||
|
|
44
|
+
/Cannot query field "\w+" on type "Query"/i.test(entry.message),
|
|
36
45
|
);
|
|
37
46
|
}
|
|
38
47
|
|
|
@@ -71,6 +80,18 @@ export const OPPORTUNITY_PRODUCT: EntityShape = {
|
|
|
71
80
|
capSingular: "OpportunityProduct",
|
|
72
81
|
capPlural: "OpportunityProducts",
|
|
73
82
|
};
|
|
83
|
+
export const ORGANIZATION: EntityShape = {
|
|
84
|
+
singular: "organization",
|
|
85
|
+
plural: "organizations",
|
|
86
|
+
capSingular: "Organization",
|
|
87
|
+
capPlural: "Organizations",
|
|
88
|
+
};
|
|
89
|
+
export const PRODUCT: EntityShape = {
|
|
90
|
+
singular: "product",
|
|
91
|
+
plural: "products",
|
|
92
|
+
capSingular: "Product",
|
|
93
|
+
capPlural: "Products",
|
|
94
|
+
};
|
|
74
95
|
export const NOTE: EntityShape = {
|
|
75
96
|
singular: "note",
|
|
76
97
|
plural: "notes",
|
|
@@ -471,11 +492,19 @@ export async function upsertNotes(options: {
|
|
|
471
492
|
return false;
|
|
472
493
|
});
|
|
473
494
|
|
|
495
|
+
// createdAt is replayed from LastMile so the activity feed reads in the order
|
|
496
|
+
// reps actually wrote the notes. Twenty accepts it on create AND update, so
|
|
497
|
+
// notes seeded before this behaviour existed heal on the next run (their
|
|
498
|
+
// content hash changes when createdAt joins it).
|
|
474
499
|
const mapped: MappedRecord[] = resolvable.map((note) => ({
|
|
475
500
|
sourceId: note.sourceId,
|
|
476
501
|
input: {
|
|
477
502
|
title: note.title,
|
|
478
503
|
bodyV2: { markdown: note.bodyMarkdown },
|
|
504
|
+
...(note.createdAt
|
|
505
|
+
? { createdAt: note.createdAt, updatedAt: note.createdAt }
|
|
506
|
+
: {}),
|
|
507
|
+
...(note.authorName ? { author: note.authorName } : {}),
|
|
479
508
|
sourceId: note.sourceId,
|
|
480
509
|
},
|
|
481
510
|
warnings: [],
|
|
@@ -499,41 +528,106 @@ export async function upsertNotes(options: {
|
|
|
499
528
|
|
|
500
529
|
// NoteTarget is ensured UNCONDITIONALLY — including for hash-skipped notes —
|
|
501
530
|
// so a crash between the Note write and the NoteTarget write heals on
|
|
502
|
-
// re-run (plan U6).
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
}
|
|
516
|
-
|
|
531
|
+
// re-run (plan U6). The existence check is BATCHED: one paginated
|
|
532
|
+
// `noteTargets` query per QUERY_PAGE notes rather than one query per note.
|
|
533
|
+
// The per-note form dominated a steady-state run — every already-paired note
|
|
534
|
+
// (thousands of them) cost a round-trip at the API rate limit, ~20 min of a
|
|
535
|
+
// 26 min run. Batched, the same phase is a handful of queries.
|
|
536
|
+
if (!dryRun) {
|
|
537
|
+
const pairs = resolvable
|
|
538
|
+
.map((note) => ({
|
|
539
|
+
note,
|
|
540
|
+
noteId: noteIdBySourceId.get(note.sourceId),
|
|
541
|
+
targetId: targetIdBySourceId.get(note.targetSourceId),
|
|
542
|
+
}))
|
|
543
|
+
.filter(
|
|
544
|
+
(p): p is { note: MappedNote; noteId: string; targetId: string } =>
|
|
545
|
+
Boolean(p.noteId) && Boolean(p.targetId),
|
|
517
546
|
);
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
547
|
+
|
|
548
|
+
// Which noteIds already have a target? Paginate within each chunk so a
|
|
549
|
+
// multi-target note can never be truncated into a false "unpaired".
|
|
550
|
+
type NoteTargetPage = {
|
|
551
|
+
noteTargets: {
|
|
552
|
+
edges: Array<{ node: { noteId: string } }>;
|
|
553
|
+
pageInfo: { hasNextPage: boolean; endCursor: string | null };
|
|
554
|
+
};
|
|
555
|
+
};
|
|
556
|
+
const alreadyPaired = new Set<string>();
|
|
557
|
+
const noteIds = [...new Set(pairs.map((p) => p.noteId))];
|
|
558
|
+
for (const page of chunk(noteIds, QUERY_PAGE)) {
|
|
559
|
+
let after: string | null = null;
|
|
560
|
+
try {
|
|
561
|
+
do {
|
|
562
|
+
const data: NoteTargetPage =
|
|
563
|
+
await client.requestWithRetry<NoteTargetPage>(
|
|
564
|
+
"/graphql",
|
|
565
|
+
`query MigrationNoteTargets($filter: NoteTargetFilterInput, $after: String) {
|
|
566
|
+
noteTargets(filter: $filter, first: ${QUERY_PAGE}, after: $after) {
|
|
567
|
+
edges { node { noteId } }
|
|
568
|
+
pageInfo { hasNextPage endCursor }
|
|
569
|
+
}
|
|
570
|
+
}`,
|
|
571
|
+
{ filter: { noteId: { in: [...page] } }, after },
|
|
572
|
+
);
|
|
573
|
+
for (const { node } of data.noteTargets.edges)
|
|
574
|
+
alreadyPaired.add(node.noteId);
|
|
575
|
+
after = data.noteTargets.pageInfo.hasNextPage
|
|
576
|
+
? data.noteTargets.pageInfo.endCursor
|
|
577
|
+
: null;
|
|
578
|
+
} while (after);
|
|
579
|
+
} catch (error) {
|
|
580
|
+
counters.failed += page.length;
|
|
581
|
+
counters.gaps.push(
|
|
582
|
+
`noteTarget lookup batch failed: ${
|
|
583
|
+
error instanceof Error ? error.message.slice(0, 300) : String(error)
|
|
584
|
+
}`,
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Create the missing targets, grouped by FK field, in BATCH_LIMIT chunks
|
|
590
|
+
// (createNoteTargets takes an array).
|
|
591
|
+
const toCreate = new Map<
|
|
592
|
+
string,
|
|
593
|
+
Array<{ noteId: string; targetId: string }>
|
|
594
|
+
>();
|
|
595
|
+
for (const p of pairs) {
|
|
596
|
+
if (alreadyPaired.has(p.noteId)) continue;
|
|
597
|
+
const field =
|
|
598
|
+
p.note.targetKind === "company"
|
|
521
599
|
? "targetCompanyId"
|
|
522
600
|
: "targetOpportunityId";
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
601
|
+
const list = toCreate.get(field) ?? [];
|
|
602
|
+
list.push({ noteId: p.noteId, targetId: p.targetId });
|
|
603
|
+
toCreate.set(field, list);
|
|
604
|
+
}
|
|
605
|
+
for (const [field, list] of toCreate) {
|
|
606
|
+
for (const batch of chunk(list, BATCH_LIMIT)) {
|
|
607
|
+
try {
|
|
608
|
+
await client.requestOnce(
|
|
609
|
+
"/graphql",
|
|
610
|
+
`mutation MigrationCreateNoteTargets($data: [NoteTargetCreateInput!]!) {
|
|
611
|
+
createNoteTargets(data: $data) { id }
|
|
612
|
+
}`,
|
|
613
|
+
{
|
|
614
|
+
data: batch.map((p) => ({
|
|
615
|
+
noteId: p.noteId,
|
|
616
|
+
[field]: p.targetId,
|
|
617
|
+
})),
|
|
618
|
+
},
|
|
619
|
+
);
|
|
620
|
+
} catch (error) {
|
|
621
|
+
counters.failed += batch.length;
|
|
622
|
+
counters.gaps.push(
|
|
623
|
+
`noteTarget create batch (${field}) failed: ${
|
|
624
|
+
error instanceof Error
|
|
625
|
+
? error.message.slice(0, 300)
|
|
626
|
+
: String(error)
|
|
627
|
+
}`,
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
537
631
|
}
|
|
538
632
|
}
|
|
539
633
|
|
|
@@ -592,11 +686,19 @@ export async function upsertOpportunityProducts(options: {
|
|
|
592
686
|
products: MappedOpportunityProduct[];
|
|
593
687
|
/** opportunity sourceId -> Twenty opportunity id. */
|
|
594
688
|
opportunityIdBySourceId: ReadonlyMap<string, string>;
|
|
689
|
+
/** catalog product sourceId -> Twenty product id. */
|
|
690
|
+
productIdBySourceId: ReadonlyMap<string, string>;
|
|
595
691
|
dryRun: boolean;
|
|
596
692
|
counters: EntityCounters;
|
|
597
693
|
}): Promise<void> {
|
|
598
|
-
const {
|
|
599
|
-
|
|
694
|
+
const {
|
|
695
|
+
client,
|
|
696
|
+
products,
|
|
697
|
+
opportunityIdBySourceId,
|
|
698
|
+
productIdBySourceId,
|
|
699
|
+
dryRun,
|
|
700
|
+
counters,
|
|
701
|
+
} = options;
|
|
600
702
|
|
|
601
703
|
const resolvable: MappedRecord[] = [];
|
|
602
704
|
for (const product of products) {
|
|
@@ -611,9 +713,24 @@ export async function upsertOpportunityProducts(options: {
|
|
|
611
713
|
);
|
|
612
714
|
continue;
|
|
613
715
|
}
|
|
716
|
+
// A line whose brand did not map to a catalog product still migrates with
|
|
717
|
+
// its quantity and amount; it simply has no product. The warning already
|
|
718
|
+
// rode along from the mapper.
|
|
719
|
+
const productId = product.productSourceId
|
|
720
|
+
? (productIdBySourceId.get(product.productSourceId) ?? null)
|
|
721
|
+
: null;
|
|
722
|
+
if (product.productSourceId && !productId) {
|
|
723
|
+
counters.gaps.push(
|
|
724
|
+
`line ${product.sourceId}: catalog product ${product.productSourceId} missing`,
|
|
725
|
+
);
|
|
726
|
+
}
|
|
614
727
|
resolvable.push({
|
|
615
728
|
sourceId: product.sourceId,
|
|
616
|
-
input: {
|
|
729
|
+
input: {
|
|
730
|
+
...product.input,
|
|
731
|
+
opportunityId,
|
|
732
|
+
...(productId ? { productId } : {}),
|
|
733
|
+
},
|
|
617
734
|
warnings: product.warnings,
|
|
618
735
|
});
|
|
619
736
|
}
|